diff --git a/src/wasi/WASI02.cpp b/src/wasi/WASI02.cpp index c92b4ef91..37119e4ed 100644 --- a/src/wasi/WASI02.cpp +++ b/src/wasi/WASI02.cpp @@ -28,16 +28,16 @@ class ComponentResourceWasiStream : public ComponentResource { friend class ComponentResourceWasiPollable; public: - ComponentResourceWasiStream(ComponentTypeResource* type, int fileNo) + ComponentResourceWasiStream(ComponentTypeResource* type, FILE* file) : ComponentResource(ResourceWasiStreamKind, type) - , m_fileNo(fileNo) + , m_file(file) , m_pollableCount(0) { } - int fileNo() const + FILE* file() const { - return m_fileNo; + return m_file; } size_t pollableCount() const @@ -46,7 +46,7 @@ class ComponentResourceWasiStream : public ComponentResource { } private: - int m_fileNo; + FILE* m_file; size_t m_pollableCount; }; @@ -99,19 +99,19 @@ static ComponentResourceWasiStream* asStream(ComponentHandle* handle) class LiftedWasiFunction : public LiftedFunction { public: enum Type { - cliExit026, - ioPollableBlock026, - ioOutputStreamCheckWrite026, - ioOutputStreamWrite026, - ioOutputStreamBlockingWriteAndFlush026, - ioOutputStreamBlockingFlush026, - ioOutputStreamSubscribe026, - cliGetStdin026, - cliGetStdout026, - cliGetStderr026, - cliGetTerminalStdin026, - cliGetTerminalStdout026, - cliGetTerminalStderr026, + cliExit02, + ioPollableBlock02, + ioOutputStreamCheckWrite02, + ioOutputStreamWrite02, + ioOutputStreamBlockingWriteAndFlush02, + ioOutputStreamBlockingFlush02, + ioOutputStreamSubscribe02, + cliGetStdin02, + cliGetStdout02, + cliGetStderr02, + cliGetTerminalStdin02, + cliGetTerminalStdout02, + cliGetTerminalStderr02, }; LiftedWasiFunction(Type type, ComponentInstance* instance, FunctionType* functionType) @@ -164,12 +164,12 @@ class ComponentInstanceWasi02 { } } - ComponentInstance* loadInstance(std::string& name); + ComponentInstance* loadInstance(const char* name, size_t length); private: static void aliasExport(ComponentInstance* instance, const char* name, ComponentRefCounted* type); static void addExport(ComponentInstance* instance, const char* name, LiftedWasiFunction::Type type, FunctionType* functionType); - ComponentInstance* getInstance(const char* name); + ComponentInstance* getInstance(const char* name, const char* postfix, size_t postfixLength); Store* m_store; DefinedFunctionTypes& m_functionTypes; @@ -191,123 +191,173 @@ void ComponentInstanceWasi02::addExport(ComponentInstance* instance, const char* instance->m_funcs.push_back(new LiftedWasiFunction(type, instance, functionType)); } -ComponentInstance* ComponentInstanceWasi02::getInstance(const char* name) +ComponentInstance* ComponentInstanceWasi02::getInstance(const char* name, const char* postfix, size_t postfixLength) { - std::string str(name); + size_t length = strlen(name); + ASSERT(length < 62); + char buffer[64]; + memcpy(buffer, name, length); + memcpy(buffer + length, postfix, postfixLength); + std::string str(buffer, length + postfixLength); return wasi02LoadInstance(m_store, m_functionTypes, str); } -ComponentInstance* ComponentInstanceWasi02::loadInstance(std::string& name) +static bool compareName(const char* name, size_t length, const char* expected) { - if (name == "wasi:cli/exit@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - addExport(instance, "exit", LiftedWasiFunction::cliExit026, m_functionTypes[DefinedFunctionTypes::I32R]); - return instance; - } - if (name == "wasi:io/error@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ - return instance; - } - if (name == "wasi:io/poll@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ - addExport(instance, "[method]pollable.block", LiftedWasiFunction::ioPollableBlock026, m_functionTypes[DefinedFunctionTypes::I32R]); - return instance; - } - if (name == "wasi:io/streams@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ - m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 1 */ - - ComponentInstance* errorIntance = getInstance("wasi:io/error@0.2.6"); - instance->m_instances.push_back(errorIntance); - aliasExport(instance, "error", errorIntance->type()->getType(0)); /* 2 */ - ComponentInstance* pollIntance = getInstance("wasi:io/poll@0.2.6"); - instance->m_instances.push_back(pollIntance); - aliasExport(instance, "pollable", pollIntance->type()->getType(0)); /* 3 */ - addExport(instance, "[method]output-stream.check-write", LiftedWasiFunction::ioOutputStreamCheckWrite026, m_functionTypes[DefinedFunctionTypes::I32I32R]); - addExport(instance, "[method]output-stream.write", LiftedWasiFunction::ioOutputStreamWrite026, m_functionTypes[DefinedFunctionTypes::I32I32I32I32R]); - addExport(instance, "[method]output-stream.blocking-write-and-flush", LiftedWasiFunction::ioOutputStreamBlockingWriteAndFlush026, m_functionTypes[DefinedFunctionTypes::I32I32I32I32R]); - addExport(instance, "[method]output-stream.blocking-flush", LiftedWasiFunction::ioOutputStreamBlockingFlush026, m_functionTypes[DefinedFunctionTypes::I32I32R]); - addExport(instance, "[method]output-stream.subscribe", LiftedWasiFunction::ioOutputStreamSubscribe026, m_functionTypes[DefinedFunctionTypes::I32_RI32]); - return instance; - } - if (name == "wasi:cli/stdin@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - - ComponentInstance* streamsIntance = getInstance("wasi:io/streams@0.2.6"); - instance->m_instances.push_back(streamsIntance); - aliasExport(instance, "input-stream", streamsIntance->type()->getType(0)); /* 0 */ - addExport(instance, "get-stdin", LiftedWasiFunction::cliGetStdin026, m_functionTypes[DefinedFunctionTypes::RI32]); - return instance; - } - if (name == "wasi:cli/stdout@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - - ComponentInstance* streamsIntance = getInstance("wasi:io/streams@0.2.6"); - instance->m_instances.push_back(streamsIntance); - aliasExport(instance, "output-stream", streamsIntance->type()->getType(1)); /* 0 */ - addExport(instance, "get-stdout", LiftedWasiFunction::cliGetStdout026, m_functionTypes[DefinedFunctionTypes::RI32]); - return instance; + if (strlen(expected) != length) { + return false; } - if (name == "wasi:cli/stderr@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - - ComponentInstance* streamsIntance = getInstance("wasi:io/streams@0.2.6"); - instance->m_instances.push_back(streamsIntance); - aliasExport(instance, "output-stream", streamsIntance->type()->getType(1)); /* 0 */ - addExport(instance, "get-stderr", LiftedWasiFunction::cliGetStderr026, m_functionTypes[DefinedFunctionTypes::RI32]); - return instance; + return memcmp(name, expected, length) == 0; +} + +ComponentInstance* ComponentInstanceWasi02::loadInstance(const char* name, size_t length) +{ + if (length < 12 || memcmp(name, "wasi:", 5) != 0) { + return nullptr; } - if (name == "wasi:cli/terminal-input@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ - return instance; + + if (name[length - 1] < '0' || name[length - 1] > '9') { + return nullptr; } - if (name == "wasi:cli/terminal-output@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ - return instance; + + size_t postfixLength = 1; + if (name[length - 2] != '.') { + postfixLength = 2; + if (name[length - 1] > '1' || name[length - 2] != '1' || name[length - 3] != '.') { + return nullptr; + } } - if (name == "wasi:cli/terminal-stdin@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - - ComponentInstance* inputIntance = getInstance("wasi:cli/terminal-input@0.2.6"); - instance->m_instances.push_back(inputIntance); - aliasExport(instance, "terminal-input", inputIntance->type()->getType(0)); /* 0 */ - addExport(instance, "get-terminal-stdin", LiftedWasiFunction::cliGetTerminalStdin026, m_functionTypes[DefinedFunctionTypes::I32R]); - return instance; + + length -= postfixLength; + const char* postfix = name + length; + + if (memcmp(name + length - 5, "@0.2.", 5) != 0) { + return nullptr; } - if (name == "wasi:cli/terminal-stdout@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - - ComponentInstance* outputIntance = getInstance("wasi:cli/terminal-output@0.2.6"); - instance->m_instances.push_back(outputIntance); - aliasExport(instance, "terminal-output", outputIntance->type()->getType(0)); /* 0 */ - addExport(instance, "get-terminal-stdout", LiftedWasiFunction::cliGetTerminalStdout026, m_functionTypes[DefinedFunctionTypes::I32R]); - return instance; + length -= 5; + + if (length > 8 && memcmp(name, "wasi:io/", 8) == 0) { + name += 8; + length -= 8; + + if (compareName(name, length, "error")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ + return instance; + } + if (compareName(name, length, "poll")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ + addExport(instance, "[method]pollable.block", LiftedWasiFunction::ioPollableBlock02, m_functionTypes[DefinedFunctionTypes::I32R]); + return instance; + } + if (compareName(name, length, "streams")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ + m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 1 */ + + ComponentInstance* errorIntance = getInstance("wasi:io/error@0.2.", postfix, postfixLength); + instance->m_instances.push_back(errorIntance); + aliasExport(instance, "error", errorIntance->type()->getType(0)); /* 2 */ + ComponentInstance* pollIntance = getInstance("wasi:io/poll@0.2.", postfix, postfixLength); + instance->m_instances.push_back(pollIntance); + aliasExport(instance, "pollable", pollIntance->type()->getType(0)); /* 3 */ + addExport(instance, "[method]output-stream.check-write", LiftedWasiFunction::ioOutputStreamCheckWrite02, m_functionTypes[DefinedFunctionTypes::I32I32R]); + addExport(instance, "[method]output-stream.write", LiftedWasiFunction::ioOutputStreamWrite02, m_functionTypes[DefinedFunctionTypes::I32I32I32I32R]); + addExport(instance, "[method]output-stream.blocking-write-and-flush", LiftedWasiFunction::ioOutputStreamBlockingWriteAndFlush02, m_functionTypes[DefinedFunctionTypes::I32I32I32I32R]); + addExport(instance, "[method]output-stream.blocking-flush", LiftedWasiFunction::ioOutputStreamBlockingFlush02, m_functionTypes[DefinedFunctionTypes::I32I32R]); + addExport(instance, "[method]output-stream.subscribe", LiftedWasiFunction::ioOutputStreamSubscribe02, m_functionTypes[DefinedFunctionTypes::I32_RI32]); + return instance; + } + return nullptr; } - if (name == "wasi:cli/terminal-stderr@0.2.6") { - m_type = new ComponentType(ComponentType::ComponentTypeKind); - ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); - - ComponentInstance* outputIntance = getInstance("wasi:cli/terminal-output@0.2.6"); - instance->m_instances.push_back(outputIntance); - aliasExport(instance, "terminal-output", outputIntance->type()->getType(0)); /* 0 */ - addExport(instance, "get-terminal-stderr", LiftedWasiFunction::cliGetTerminalStderr026, m_functionTypes[DefinedFunctionTypes::I32R]); - return instance; + + if (length > 9 && memcmp(name, "wasi:cli/", 9) == 0) { + name += 9; + length -= 9; + + if (compareName(name, length, "exit")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + addExport(instance, "exit", LiftedWasiFunction::cliExit02, m_functionTypes[DefinedFunctionTypes::I32R]); + return instance; + } + if (compareName(name, length, "stdin")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + + ComponentInstance* streamsIntance = getInstance("wasi:io/streams@0.2.", postfix, postfixLength); + instance->m_instances.push_back(streamsIntance); + aliasExport(instance, "input-stream", streamsIntance->type()->getType(0)); /* 0 */ + addExport(instance, "get-stdin", LiftedWasiFunction::cliGetStdin02, m_functionTypes[DefinedFunctionTypes::RI32]); + return instance; + } + if (compareName(name, length, "stdout")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + + ComponentInstance* streamsIntance = getInstance("wasi:io/streams@0.2.", postfix, postfixLength); + instance->m_instances.push_back(streamsIntance); + aliasExport(instance, "output-stream", streamsIntance->type()->getType(1)); /* 0 */ + addExport(instance, "get-stdout", LiftedWasiFunction::cliGetStdout02, m_functionTypes[DefinedFunctionTypes::RI32]); + return instance; + } + if (compareName(name, length, "stderr")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + + ComponentInstance* streamsIntance = getInstance("wasi:io/streams@0.2.", postfix, postfixLength); + instance->m_instances.push_back(streamsIntance); + aliasExport(instance, "output-stream", streamsIntance->type()->getType(1)); /* 0 */ + addExport(instance, "get-stderr", LiftedWasiFunction::cliGetStderr02, m_functionTypes[DefinedFunctionTypes::RI32]); + return instance; + } + if (compareName(name, length, "terminal-input")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ + return instance; + } + if (compareName(name, length, "terminal-output")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + m_type->pushType(new ComponentTypeResource(false, ComponentTypeResource::NotDefined)); /* 0 */ + return instance; + } + if (compareName(name, length, "terminal-stdin")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + + ComponentInstance* inputIntance = getInstance("wasi:cli/terminal-input@0.2.", postfix, postfixLength); + instance->m_instances.push_back(inputIntance); + aliasExport(instance, "terminal-input", inputIntance->type()->getType(0)); /* 0 */ + addExport(instance, "get-terminal-stdin", LiftedWasiFunction::cliGetTerminalStdin02, m_functionTypes[DefinedFunctionTypes::I32R]); + return instance; + } + if (compareName(name, length, "terminal-stdout")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + + ComponentInstance* outputIntance = getInstance("wasi:cli/terminal-output@0.2.", postfix, postfixLength); + instance->m_instances.push_back(outputIntance); + aliasExport(instance, "terminal-output", outputIntance->type()->getType(0)); /* 0 */ + addExport(instance, "get-terminal-stdout", LiftedWasiFunction::cliGetTerminalStdout02, m_functionTypes[DefinedFunctionTypes::I32R]); + return instance; + } + if (compareName(name, length, "terminal-stderr")) { + m_type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = ComponentInstance::createInstance(m_store, m_type); + + ComponentInstance* outputIntance = getInstance("wasi:cli/terminal-output@0.2.", postfix, postfixLength); + instance->m_instances.push_back(outputIntance); + aliasExport(instance, "terminal-output", outputIntance->type()->getType(0)); /* 0 */ + addExport(instance, "get-terminal-stderr", LiftedWasiFunction::cliGetTerminalStderr02, m_functionTypes[DefinedFunctionTypes::I32R]); + return instance; + } + return nullptr; } return nullptr; } @@ -320,7 +370,7 @@ ComponentInstance* wasi02LoadInstance(Store* store, DefinedFunctionTypes& functi } ComponentInstanceWasi02 instanceCreator(store, functionTypes); - instance = instanceCreator.loadInstance(name); + instance = instanceCreator.loadInstance(name.data(), name.length()); store->registerComponentInstance(name, instance); return instance; } @@ -335,7 +385,34 @@ void callWasiFunction(ExecutionState& state, Value* argv, Value* result, LiftedW ComponentInstance* instance = function->instance(); switch (function->type()) { - case LiftedWasiFunction::ioOutputStreamSubscribe026: { + case LiftedWasiFunction::ioOutputStreamCheckWrite02: { + uint32_t offset = argv[1].asI32(); + uint64_t value = 0xffffffff; + options->memory()->store(state, offset, 8, value); + options->memory()->buffer()[offset] = 0; + break; + } + case LiftedWasiFunction::ioOutputStreamWrite02: { + uint32_t index = argv[0].asI32(); + ComponentHandle* handle = options->instance()->getHandle(state, index); + if (handle->kind() != ComponentHandle::ResourceWasiStreamKind) { + ComponentInstance::throwInvalidHandle(state, index); + } + + uint32_t bufferStart = argv[1].asI32(); + uint32_t bufferLength = argv[2].asI32(); + fwrite(options->memory()->buffer() + bufferStart, bufferLength, 1, asStream(handle)->file()); + + uint32_t offset = argv[3].asI32(); + options->memory()->buffer()[offset] = 0; + break; + } + case LiftedWasiFunction::ioOutputStreamBlockingFlush02: { + uint32_t offset = argv[1].asI32(); + options->memory()->buffer()[offset] = 0; + break; + } + case LiftedWasiFunction::ioOutputStreamSubscribe02: { uint32_t index = argv[0].asI32(); ComponentHandle* handle = options->instance()->getHandle(state, index); if (handle->kind() != ComponentHandle::ResourceWasiStreamKind) { @@ -346,12 +423,12 @@ void callWasiFunction(ExecutionState& state, Value* argv, Value* result, LiftedW result[0] = Value(static_cast(options->instance()->appendHandle(state, resource))); break; } - case LiftedWasiFunction::cliGetStdout026: { - ComponentResource* resource = new ComponentResourceWasiStream(instance->type()->getType(0)->asTypeResource(), 1); + case LiftedWasiFunction::cliGetStdout02: { + ComponentResource* resource = new ComponentResourceWasiStream(instance->type()->getType(0)->asTypeResource(), stdout); result[0] = Value(static_cast(options->instance()->appendHandle(state, resource))); break; } - case LiftedWasiFunction::cliGetTerminalStdout026: { + case LiftedWasiFunction::cliGetTerminalStdout02: { ComponentResource* resource = new ComponentResourceWasiTerminal(instance->type()->getType(0)->asTypeResource(), 1); uint32_t offset = argv[0].asI32(); uint32_t value = options->instance()->appendHandle(state, resource);