-
Notifications
You must be signed in to change notification settings - Fork 695
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial MVP of WASI API support to wasm-interp
This is proof of concept that only implements the `proc_exit` API. Extending this to the full WASI API will to follow assuming this approach seems reasonable. Fixes #1409
- Loading branch information
Showing
14 changed files
with
446 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
/* | ||
* Copyright 2020 WebAssembly Community Group participants | ||
* | ||
* 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. | ||
*/ | ||
|
||
#include "src/interp/interp-wasi.h" | ||
#include "src/interp/interp-util.h" | ||
|
||
#ifdef WITH_WASI | ||
|
||
#include "uvwasi.h" | ||
|
||
#include <unordered_map> | ||
|
||
using namespace wabt; | ||
using namespace wabt::interp; | ||
|
||
namespace { | ||
|
||
class WasiInstance { | ||
public: | ||
WasiInstance(Instance* instance, | ||
uvwasi_s* uvwasi, | ||
Memory* memory, | ||
Stream* trace_stream) | ||
: instance(instance), | ||
uvwasi(uvwasi), | ||
memory(memory), | ||
trace_stream(trace_stream) {} | ||
|
||
Instance* instance; | ||
uvwasi_s* uvwasi; | ||
// The memory accociated with the instance. Looked up once on startup | ||
// and cached here. | ||
Memory* memory; | ||
// The trace stream accosiated with the instance. | ||
Stream* trace_stream; | ||
|
||
Result proc_exit(const Values& params, Values& results, Trap::Ptr* trap) { | ||
const Value arg0 = params[0]; | ||
uvwasi_proc_exit(uvwasi, arg0.i32_); | ||
return Result::Ok; | ||
} | ||
|
||
Result fd_write(const Values& params, Values& results, Trap::Ptr* trap) { | ||
const Value arg0 = params[0]; | ||
int32_t iovptr = params[1].i32_; | ||
int32_t iovcnt = params[2].i32_; | ||
uvwasi_ciovec_t* iovs = getMemPtr<uvwasi_ciovec_t>(iovptr, iovcnt); | ||
//printf("got iovs = %p\n", iovs); | ||
//printf("iovs[0].iov_len = %d\n", iovs[0].buf_len); | ||
uint32_t out; | ||
//uvwasi_ciovec_t** iovs = new uvwasi_ciovec_t*[iovcnt]; | ||
//uvwasi_ciovec_t* iov_data = new uvwasi_ciovec_t[iovcnt]; | ||
// uint32_t* out_size = NULL;//(uint32_t*)getMemoryAddress(arg3); | ||
uvwasi_fd_write(uvwasi, arg0.i32_, iovs, iovcnt, &out); | ||
//delete[] iovs; | ||
return Result::Ok; | ||
} | ||
|
||
protected: | ||
template <typename T> | ||
T* getMemPtr(uint32_t address, uint32_t size) { | ||
printf("getMemPtr address=%d size=%d(%lu)\n", address, size, | ||
size * sizeof(T)); | ||
if (!memory->IsValidAccess(address, 0, size * sizeof(T))) { | ||
printf("invalid access\n"); | ||
} | ||
return reinterpret_cast<T*>(memory->UnsafeData() + address); | ||
} | ||
}; | ||
|
||
std::unordered_map<Instance*, WasiInstance*> wasiInstances; | ||
|
||
// TODO(sbc): Auto-generate this. | ||
|
||
#define WASI_CALLBACK(NAME) \ | ||
Result NAME(Thread& thread, const Values& params, Values& results, \ | ||
Trap::Ptr* trap) { \ | ||
Instance* instance = thread.GetCallerInstance(); \ | ||
assert(instance); \ | ||
WasiInstance* wasi_instance = wasiInstances[instance]; \ | ||
if (wasi_instance->trace_stream) { \ | ||
wasi_instance->trace_stream->Writef( \ | ||
">>> running wasi function \"%s\":\n", #NAME); \ | ||
} \ | ||
return wasi_instance->NAME(params, results, trap); \ | ||
} | ||
|
||
WASI_CALLBACK(proc_exit); | ||
WASI_CALLBACK(fd_write); | ||
|
||
} // namespace | ||
|
||
namespace wabt { | ||
namespace interp { | ||
|
||
Result WasiBindImports(const Module::Ptr& module, | ||
RefVec& imports, | ||
Stream* stream, | ||
Stream* trace_stream) { | ||
Store* store = module.store(); | ||
for (auto&& import : module->desc().imports) { | ||
if (import.type.type->kind != ExternKind::Func) { | ||
stream->Writef("wasi error: invalid import type: %s\n", | ||
import.type.name.c_str()); | ||
return Result::Error; | ||
} | ||
|
||
if (import.type.module != "wasi_snapshot_preview1") { | ||
stream->Writef("wasi error: unknown module import: %s\n", | ||
import.type.module.c_str()); | ||
return Result::Error; | ||
} | ||
|
||
auto func_type = *cast<FuncType>(import.type.type.get()); | ||
auto import_name = StringPrintf("%s.%s", import.type.module.c_str(), | ||
import.type.name.c_str()); | ||
HostFunc::Ptr host_func; | ||
|
||
// TODO(sbc): Auto-generate this. | ||
if (import.type.name == "proc_exit") { | ||
host_func = HostFunc::New(*store, func_type, proc_exit); | ||
} else if (import.type.name == "fd_write") { | ||
host_func = HostFunc::New(*store, func_type, fd_write); | ||
} else { | ||
stream->Writef("unknown wasi_snapshot_preview1 import: %s\n", | ||
import.type.name.c_str()); | ||
return Result::Error; | ||
} | ||
imports.push_back(host_func.ref()); | ||
} | ||
|
||
return Result::Ok; | ||
} | ||
|
||
Result WasiRunStart(const Instance::Ptr& instance, | ||
uvwasi_s* uvwasi, | ||
Stream* stream, | ||
Stream* trace_stream) { | ||
Store* store = instance.store(); | ||
auto module = store->UnsafeGet<Module>(instance->module()); | ||
auto&& module_desc = module->desc(); | ||
|
||
Func::Ptr start; | ||
Memory::Ptr memory; | ||
for (auto&& export_ : module_desc.exports) { | ||
if (export_.type.name == "memory") { | ||
if (export_.type.type->kind != ExternalKind::Memory) { | ||
stream->Writef("wasi error: memory export has incorrect type\n"); | ||
return Result::Error; | ||
} | ||
memory = store->UnsafeGet<Memory>(instance->memories()[export_.index]); | ||
} | ||
if (export_.type.name == "_start") { | ||
if (export_.type.type->kind != ExternalKind::Func) { | ||
stream->Writef("wasi error: _start export is not a function\n"); | ||
return Result::Error; | ||
} | ||
start = store->UnsafeGet<Func>(instance->funcs()[export_.index]); | ||
} | ||
if (start && memory) { | ||
break; | ||
} | ||
} | ||
|
||
if (!start) { | ||
stream->Writef("wasi error: _start export not found\n"); | ||
return Result::Error; | ||
} | ||
|
||
if (!memory) { | ||
stream->Writef("wasi error: memory export not found\n"); | ||
return Result::Error; | ||
} | ||
|
||
if (start->type().params.size() || start->type().results.size()) { | ||
stream->Writef("wasi error: invalid _start signature\n"); | ||
return Result::Error; | ||
} | ||
|
||
// Register memory | ||
auto* wasi = | ||
new WasiInstance(instance.get(), uvwasi, memory.get(), trace_stream); | ||
wasiInstances[instance.get()] = wasi; | ||
|
||
// Call start ([] -> []) | ||
Values params; | ||
Values results; | ||
Trap::Ptr trap; | ||
Result res = start->Call(*store, params, results, &trap, trace_stream); | ||
if (trap) { | ||
WriteTrap(stream, " error", trap); | ||
} | ||
|
||
// Unregister memory | ||
wasiInstances.erase(instance.get()); | ||
delete wasi; | ||
return res; | ||
} | ||
|
||
} // namespace interp | ||
} // namespace wabt | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright 2020 WebAssembly Community Group participants | ||
* | ||
* 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. | ||
*/ | ||
|
||
#ifndef WABT_INTERP_WASI_H_ | ||
#define WABT_INTERP_WASI_H_ | ||
|
||
#include "src/common.h" | ||
#include "src/error.h" | ||
#include "src/interp/interp.h" | ||
|
||
#ifdef WITH_WASI | ||
|
||
struct uvwasi_s; | ||
|
||
namespace wabt { | ||
namespace interp { | ||
|
||
Result WasiBindImports(const Module::Ptr& module, | ||
RefVec& imports, | ||
Stream* stream, | ||
Stream* trace_stream); | ||
|
||
Result WasiRunStart(const Instance::Ptr& instance, | ||
uvwasi_s* uvwasi, | ||
Stream* stream, | ||
Stream* trace_stream); | ||
|
||
} // namespace interp | ||
} // namespace wabt | ||
|
||
#endif | ||
|
||
#endif /* WABT_INTERP_WASI_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
WASI_API(proc_exit, i32) |
Oops, something went wrong.