From a10f0177a35bbb722665cba18cecbd91007e0aee Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 8 May 2026 07:38:06 +0000 Subject: [PATCH] Implement instantiate Several smaller scope reworks. Tag uses function type directly. Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- src/jit/Analysis.cpp | 8 +- src/jit/ByteCodeParser.cpp | 2 +- src/jit/TryCatchInl.h | 2 +- src/parser/WASMComponentParser.cpp | 157 ++++++----- src/parser/WASMParser.cpp | 11 +- src/runtime/Component.cpp | 9 +- src/runtime/Component.h | 225 ++++++++++------ src/runtime/ComponentInstance.cpp | 418 +++++++++++++++++++++++++++++ src/runtime/ComponentInstance.h | 199 ++++++++++++++ src/runtime/DefinedFunctionTypes.h | 22 ++ src/runtime/Function.cpp | 54 +--- src/runtime/Function.h | 37 ++- src/runtime/Instance.h | 28 +- src/runtime/Module.cpp | 9 +- src/runtime/Module.h | 6 + src/runtime/Object.h | 3 + src/runtime/ObjectType.h | 8 +- src/runtime/Store.cpp | 10 + src/runtime/Store.h | 14 + src/runtime/Tag.cpp | 2 +- src/runtime/Tag.h | 4 +- src/shell/Shell.cpp | 34 ++- src/wasi/WASI02.cpp | 134 +++++++++ src/wasi/WASI02.h | 36 +++ 24 files changed, 1178 insertions(+), 254 deletions(-) create mode 100644 src/runtime/ComponentInstance.cpp create mode 100644 src/runtime/ComponentInstance.h create mode 100644 src/wasi/WASI02.cpp create mode 100644 src/wasi/WASI02.h diff --git a/src/jit/Analysis.cpp b/src/jit/Analysis.cpp index e48815764..e0001c95c 100644 --- a/src/jit/Analysis.cpp +++ b/src/jit/Analysis.cpp @@ -309,7 +309,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize) for (auto it : tryBlocks()[nextTryBlock].catchBlocks) { if (it.tagIndex != std::numeric_limits::max()) { TagType* tagType = module()->tagType(it.tagIndex); - variableCount += module()->functionType(tagType->sigIndex())->param().size(); + variableCount += tagType->functionType()->param().size(); } } @@ -370,7 +370,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize) dependencyCtx.update(it.u.handler->m_dependencyStart, label->id()); } else { TagType* tagType = module()->tagType(it.tagIndex); - const TypeVector& param = module()->functionType(tagType->sigIndex())->param(); + const TypeVector& param = tagType->functionType()->param(); Label* catchLabel = it.u.handler; m_variableList->pushCatchUpdate(catchLabel, param.size()); @@ -454,7 +454,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize) dependencyCtx.update(it.u.handler->m_dependencyStart, instr->id()); } else { TagType* tagType = module()->tagType(it.tagIndex); - const TypeVector& param = module()->functionType(tagType->sigIndex())->param(); + const TypeVector& param = tagType->functionType()->param(); Label* catchLabel = it.u.handler; dependencyCtx.update(catchLabel->m_dependencyStart, catchLabel->id(), @@ -788,7 +788,7 @@ void JITCompiler::buildVariables(uint32_t requiredStackSize) case ByteCode::ThrowOpcode: { Throw* throwTag = reinterpret_cast(instr->byteCode()); TagType* tagType = module()->tagType(throwTag->tagIndex()); - types = &module()->functionType(tagType->sigIndex())->param(); + types = &tagType->functionType()->param(); break; } default: { diff --git a/src/jit/ByteCodeParser.cpp b/src/jit/ByteCodeParser.cpp index c07caee32..7f963a0d8 100644 --- a/src/jit/ByteCodeParser.cpp +++ b/src/jit/ByteCodeParser.cpp @@ -1226,7 +1226,7 @@ static void compileFunction(JITCompiler* compiler) case ByteCode::ThrowOpcode: { Throw* throwTag = reinterpret_cast(byteCode); TagType* tagType = compiler->module()->tagType(throwTag->tagIndex()); - uint32_t size = compiler->module()->functionType(tagType->sigIndex())->param().size(); + uint32_t size = tagType->functionType()->param().size(); Instruction* instr = compiler->append(byteCode, Instruction::Any, opcode, size, 0); Operand* param = instr->params(); diff --git a/src/jit/TryCatchInl.h b/src/jit/TryCatchInl.h index ca618aeee..67a9bfcb2 100644 --- a/src/jit/TryCatchInl.h +++ b/src/jit/TryCatchInl.h @@ -248,7 +248,7 @@ static void emitThrow(sljit_compiler* compiler, Instruction* instr) CompileContext* context = CompileContext::get(compiler); Throw* throwTag = reinterpret_cast(instr->byteCode()); TagType* tagType = context->compiler->module()->tagType(throwTag->tagIndex()); - const TypeVector& types = context->compiler->module()->functionType(tagType->sigIndex())->param(); + const TypeVector& types = tagType->functionType()->param(); emitStoreOntoStack(compiler, instr->params(), throwTag->dataOffsets(), types, false); diff --git a/src/parser/WASMComponentParser.cpp b/src/parser/WASMComponentParser.cpp index b0f8efd69..55e8906ac 100644 --- a/src/parser/WASMComponentParser.cpp +++ b/src/parser/WASMComponentParser.cpp @@ -28,23 +28,20 @@ namespace wabt { class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate { private: struct CoreInstanceType { - static constexpr size_t NotInline = ~static_cast(0); - - CoreInstanceType(Walrus::Module* module) + CoreInstanceType(Walrus::Module* module, uint32_t index) : module(module) - , inlineIndex(NotInline) + , index(index) { - ASSERT(module != nullptr); } - CoreInstanceType(size_t inlineIndex) + CoreInstanceType(uint32_t index) : module(nullptr) - , inlineIndex(inlineIndex) + , index(index) { } Walrus::Module* module; - size_t inlineIndex; + uint32_t index; }; // Depth data for each component. @@ -53,15 +50,16 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate : parent(parent) , parentComponentType(parentComponentType) , parentComponent(parentComponent) + , coreInstanceCounter(0) { } ComponentTypeInfo* parent; Walrus::ComponentType* parentComponentType; Walrus::Component* parentComponent; + uint32_t coreInstanceCounter; std::vector coreFuncTypes; std::vector coreMemories; - std::vector coreModuleTypes; std::vector coreInstanceTypes; std::vector funcTypes; std::vector componentTypes; @@ -286,10 +284,8 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate if (!result.second.empty()) { m_walrusParseError = result.second; } - // Module has been already added to store. - Walrus::Module* module = result.first.value(); - m_currentComponent->pushDeclaration(new Walrus::ComponentCoreModule(module)); - m_currentInfo->coreModuleTypes.push_back(module); + // Module has already been added to store. + m_currentComponent->pushModule(result.first.value()); } void BeginComponent(uint32_t version, size_t depth) @@ -297,11 +293,11 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate ASSERT(m_currentInfo != nullptr || (m_current == nullptr && m_currentComponent == nullptr)); Walrus::Component* parentComponent = m_currentComponent; m_currentInfo = new ComponentTypeInfo(m_currentInfo, m_current, m_currentComponent); - m_currentComponent = new Walrus::Component(); + m_currentComponent = new Walrus::Component(m_store); m_current = m_currentComponent->type(); if (parentComponent != nullptr) { - parentComponent->pushDeclaration(m_currentComponent); + parentComponent->pushComponent(m_currentComponent); m_currentInfo->parent->componentTypes.push_back(m_current); } } @@ -309,6 +305,10 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate void EndComponent() { ComponentTypeInfo* info = m_currentInfo; + if (m_currentComponent->coreInlineExportsStarts().size() > 0) { + // Extra value for coreInlineExportsEnd() calls. + m_currentComponent->coreInlineExportsStarts().push_back(m_currentComponent->coreInlineExports().size()); + } // Keep the last component. if (m_currentInfo->parentComponent != nullptr) { m_currentComponent = m_currentInfo->parentComponent; @@ -322,8 +322,9 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate void BeginCoreInstance(Index moduleIndex, uint32_t argumentCount) { - m_currentInfo->coreInstanceTypes.push_back(CoreInstanceType(m_currentInfo->coreModuleTypes[moduleIndex])); + m_currentInfo->coreInstanceTypes.push_back(CoreInstanceType(m_currentComponent->modules()[moduleIndex], m_currentInfo->coreInstanceCounter++)); m_currentComponent->pushDeclaration(new Walrus::ComponentCoreInstantiate(moduleIndex)); + ASSERT(~static_cast(m_currentComponent->coreInlineExportsStarts().size()) >= m_currentInfo->coreInstanceCounter); } void OnCoreInstanceArg(const ComponentStringLoc& name, @@ -331,7 +332,7 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate Index index) { Walrus::ComponentCoreInstantiate* instance = m_currentComponent->declarations().back()->asCoreInstantiate(); - instance->arguments().push_back(Walrus::ComponentCoreInstantiate::Argument{ name.str.to_string(), index }); + instance->arguments().push_back(Walrus::ComponentCoreInstantiate::Argument{ name.str.to_string(), m_currentInfo->coreInstanceTypes[index].index }); } void EndCoreInstance() @@ -340,59 +341,21 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate void BeginInlineCoreInstance(uint32_t argumentCount) { - m_currentInfo->coreInstanceTypes.push_back(CoreInstanceType(m_currentComponent->declarations().size())); - m_currentComponent->pushDeclaration(new Walrus::ComponentCoreInstantiateInline()); - ASSERT(m_names.size() == 0); + uint32_t index = static_cast(m_currentComponent->coreInlineExportsStarts().size()); + m_currentComponent->coreInlineExportsStarts().push_back(m_currentComponent->coreInlineExports().size()); + ASSERT(~index > m_currentInfo->coreInstanceCounter); + m_currentInfo->coreInstanceTypes.push_back(CoreInstanceType(~index)); } void OnInlineCoreInstanceArg(const ComponentStringLoc& name, ComponentSort sort, Index index) { - Walrus::ComponentCoreInstantiateInline* instance = m_currentComponent->declarations().back()->asCoreInstantiateInline(); - instance->arguments().push_back(Walrus::ComponentCoreInstantiateInline::Argument{ getSort(sort), index }); - m_names.push_back(name.str.to_string()); + m_currentComponent->coreInlineExports().push_back(Walrus::Component::InlineExport{ name.str.to_string(), getSort(sort), index }); } void EndInlineCoreInstance() { - Walrus::ComponentCoreInstantiateInline* instance = m_currentComponent->declarations().back()->asCoreInstantiateInline(); - Walrus::WASMParsingResult result; - size_t size = instance->arguments().size(); - uint32_t funcIndex = 0; - uint32_t tableIndex = 0; - uint32_t memoryIndex = 0; - uint32_t globalIndex = 0; - ASSERT(m_names.size() == size); - - for (size_t i = 0; i < size; i++) { - Walrus::ExportType::Type exportType; - uint32_t index; - switch (instance->arguments()[i].sort) { - case Walrus::ComponentSort::CoreFunc: - index = funcIndex++; - exportType = Walrus::ExportType::Function; - break; - case Walrus::ComponentSort::CoreTable: - index = tableIndex++; - exportType = Walrus::ExportType::Table; - break; - case Walrus::ComponentSort::CoreMemory: - index = memoryIndex++; - exportType = Walrus::ExportType::Memory; - break; - default: - ASSERT(instance->arguments()[i].sort == Walrus::ComponentSort::CoreGlobal); - index = globalIndex++; - exportType = Walrus::ExportType::Global; - break; - } - result.m_exports.push_back(new Walrus::ExportType(exportType, m_names[i], index)); - } - Walrus::Module* module = new Walrus::Module(m_store, result); - m_currentInfo->coreInstanceTypes.back().module = module; - instance->setModule(module); - m_names.clear(); } void BeginInstance(Index componentIndex, @@ -430,8 +393,8 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate } type->addRef(); Walrus::ComponentInstantiateInline* instance = m_currentComponent->declarations().back()->asInstantiateInline(); - instance->type()->exports().push_back(Walrus::ComponentType::External{ name.str.to_string(), type }); - instance->arguments().push_back(Walrus::ComponentInstantiateInline::Argument{ getSort(sort), index }); + instance->type()->exports().push_back(Walrus::ComponentType::External{ name.str.to_string(), type, getSort(sort), kInvalidIndex }); + instance->arguments().push_back(index); } void EndInlineInstance() @@ -442,6 +405,10 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate Index instanceIndex, const ComponentStringLoc& name) { + if (sort != ComponentSort::Type) { + m_currentComponent->pushDeclaration(new Walrus::ComponentAliasExport(Walrus::ComponentDeclaration::AliasExportKind, name.str.to_string(), getSort(sort), instanceIndex)); + } + for (auto it : m_currentInfo->instanceTypes[instanceIndex]->exports()) { if (name.str == it.name) { switch (sort) { @@ -471,25 +438,26 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate Index coreInstanceIndex, const ComponentStringLoc& name) { - size_t exportIndex = 0; const CoreInstanceType& type = m_currentInfo->coreInstanceTypes[coreInstanceIndex]; - const Walrus::VectorWithFixedSize>& exports = type.module->exports(); - while (true) { - if (exportIndex >= exports.size()) { - m_walrusParseError = "export not found"; - return; - } + if (type.module == nullptr) { + size_t exportIndex = m_currentComponent->coreInlineExportsStart(~type.index); + size_t end = m_currentComponent->coreInlineExportsEnd(~type.index); + std::vector& exports = m_currentComponent->coreInlineExports(); - if (name.str == exports[exportIndex]->name()) { - break; - } - exportIndex++; - } + while (true) { + if (exportIndex >= end) { + m_walrusParseError = "export not found"; + return; + } - if (type.inlineIndex != CoreInstanceType::NotInline) { - exportIndex = m_currentComponent->declarations()[type.inlineIndex]->asCoreInstantiateInline()->arguments()[exportIndex].index; + if (name.str == exports[exportIndex].name) { + break; + } + exportIndex++; + } + exportIndex = exports[exportIndex].index; switch (sort) { case ComponentSort::CoreFunc: m_currentInfo->coreFuncTypes.push_back(m_currentInfo->coreFuncTypes[exportIndex]); @@ -500,9 +468,28 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate default: break; } + + if (sort != ComponentSort::CoreType) { + m_currentComponent->pushDeclaration(new Walrus::ComponentAliasInline(getSort(sort), exportIndex)); + } return; } + size_t exportIndex = 0; + const Walrus::VectorWithFixedSize>& exports = type.module->exports(); + + while (true) { + if (exportIndex >= exports.size()) { + m_walrusParseError = "export not found"; + return; + } + + if (name.str == exports[exportIndex]->name()) { + break; + } + exportIndex++; + } + uint32_t itemIndex = exports[exportIndex]->itemIndex(); switch (sort) { @@ -515,6 +502,10 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate default: break; } + + if (sort != ComponentSort::CoreType) { + m_currentComponent->pushDeclaration(new Walrus::ComponentAliasExport(Walrus::ComponentDeclaration::AliasCoreExportKind, name.str.to_string(), getSort(sort), type.index)); + } } void OnAliasOuter(ComponentSort sort, @@ -783,7 +774,7 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate if (m_currentComponent != nullptr) { m_currentComponent->pushDeclaration(new Walrus::ComponentImport(static_cast(m_current->imports().size()))); } - m_current->imports().push_back(Walrus::ComponentType::External{ name.str.to_string(), pushExternalType(externalInfo) }); + m_current->imports().push_back(Walrus::ComponentType::External{ name.str.to_string(), pushExternalType(externalInfo), getSort(externalInfo.sort), kInvalidIndex }); } void OnExport(const ComponentStringLoc& name, @@ -792,12 +783,13 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate ComponentExportInfo* exportInfo) { if (externalInfo != nullptr) { - m_current->exports().push_back(Walrus::ComponentType::External{ name.str.to_string(), pushExternalType(*externalInfo) }); + uint32_t exportIndex = exportInfo != nullptr ? exportInfo->index.index : kInvalidIndex; + m_current->exports().push_back(Walrus::ComponentType::External{ name.str.to_string(), pushExternalType(*externalInfo), getSort(externalInfo->sort), exportIndex }); return; } ComponentExternalInfo info{ exportInfo->sort, ComponentExternalDesc::Unused, exportInfo->index }; - m_current->exports().push_back(Walrus::ComponentType::External{ name.str.to_string(), pushExternalType(info) }); + m_current->exports().push_back(Walrus::ComponentType::External{ name.str.to_string(), pushExternalType(info), getSort(exportInfo->sort), exportInfo->index.index }); } Walrus::Component* parsingResult() @@ -814,7 +806,6 @@ class WASMComponentBinaryReader : public wabt::WASMComponentBinaryReaderDelegate Walrus::ComponentType* m_current; Walrus::Component* m_currentComponent; ComponentTypeInfo* m_currentInfo; - std::vector m_names; }; } // namespace wabt @@ -827,11 +818,13 @@ std::pair, std::string> WASMComponentParser::parseBinary(St std::string error = ReadWasmComponentBinary(data, len, &delegate); if (error.length()) { + if (delegate.parsingResult() != nullptr) { + delete delegate.parsingResult(); + } return std::make_pair(nullptr, error); } - delete delegate.parsingResult(); - return std::make_pair(nullptr, std::string()); + return std::make_pair(delegate.parsingResult(), std::string()); } } // namespace Walrus diff --git a/src/parser/WASMParser.cpp b/src/parser/WASMParser.cpp index 3b95a9e7c..05b9a30b1 100644 --- a/src/parser/WASMParser.cpp +++ b/src/parser/WASMParser.cpp @@ -1075,7 +1075,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { { ASSERT(tagIndex == m_result.m_tagTypes.size()); ASSERT(m_result.m_imports.size() == importIndex); - m_result.m_tagTypes.push_back(new Walrus::TagType(sigIndex)); + m_result.m_tagTypes.push_back(new Walrus::TagType(getFunctionType(sigIndex))); m_result.m_imports.push_back(new Walrus::ImportType( Walrus::ImportType::Tag, moduleName, fieldName, m_result.m_tagTypes[tagIndex])); @@ -1318,7 +1318,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { virtual void OnTagType(Index index, Index sigIndex) override { ASSERT(index == m_result.m_tagTypes.size()); - m_result.m_tagTypes.push_back(new Walrus::TagType(sigIndex)); + m_result.m_tagTypes.push_back(new Walrus::TagType(getFunctionType(sigIndex))); } virtual void OnStartFunction(Index funcIndex) override @@ -2330,13 +2330,13 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { uint32_t offsetsSize = 0; if (tagIndex != std::numeric_limits::max()) { - offsetsSize = getFunctionType(m_result.m_tagTypes[tagIndex]->sigIndex())->param().size(); + offsetsSize = m_result.m_tagTypes[tagIndex]->functionType()->param().size(); } pushByteCode(Walrus::Throw(tagIndex, offsetsSize), WASMOpcode::ThrowOpcode); if (tagIndex != std::numeric_limits::max()) { - auto functionType = getFunctionType(m_result.m_tagTypes[tagIndex]->sigIndex()); + auto functionType = m_result.m_tagTypes[tagIndex]->functionType(); auto& param = functionType->param().types(); expandByteCode(Walrus::ByteCode::pointerAlignedSize(sizeof(Walrus::ByteCodeStackOffset) * param.size())); ASSERT(m_currentByteCode.size() % sizeof(void*) == 0); @@ -2382,8 +2382,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_catchInfo.push_back({ m_blockInfo.size(), m_blockInfo.back().m_position, tryEnd, m_currentByteCode.size(), tagIndex }); if (tagIndex != std::numeric_limits::max()) { - auto functionType = getFunctionType(m_result.m_tagTypes[tagIndex]->sigIndex()); - auto& param = functionType->param().types(); + auto& param = m_result.m_tagTypes[tagIndex]->functionType()->param().types(); for (size_t i = 0; i < param.size(); i++) { pushVMStack(param[i]); } diff --git a/src/runtime/Component.cpp b/src/runtime/Component.cpp index d21a9ff07..857493b60 100644 --- a/src/runtime/Component.cpp +++ b/src/runtime/Component.cpp @@ -15,7 +15,8 @@ */ #include "Walrus.h" -#include "Component.h" +#include "runtime/Component.h" +#include "runtime/Store.h" namespace Walrus { @@ -83,6 +84,12 @@ void ComponentRefCounted::releaseAllRefs(ComponentRefCounted* ref) } while (ref != nullptr); } +Component::Component(Store* store) +{ + m_type = new ComponentType(ComponentRefCounted::ComponentTypeKind); + store->appendComponent(this); +} + Component::~Component() { for (auto it : m_declarations) { diff --git a/src/runtime/Component.h b/src/runtime/Component.h index 01300f402..5febf19c0 100644 --- a/src/runtime/Component.h +++ b/src/runtime/Component.h @@ -30,6 +30,7 @@ enum class ComponentSort : uint8_t { CoreTable, CoreMemory, CoreGlobal, + CoreTag, CoreType, CoreModule, CoreInstance, @@ -494,6 +495,9 @@ class ComponentType : public ComponentRefCounted { struct External { std::string name; ComponentRefCounted* type; + ComponentSort sort; + // Only needed for concreate components. + uint32_t exportIndex; }; ComponentType(Kind kind) @@ -565,6 +569,11 @@ class CanonicalOptions { return m_encoding; } + bool isAsync() const + { + return m_isAsync; + } + uint32_t memoryIndex() const { return m_memoryIndex; @@ -589,30 +598,31 @@ class CanonicalOptions { uint32_t m_callbackIndex; }; -class ComponentCoreModule; class ComponentCoreInstantiate; -class ComponentCoreInstantiateInline; class ComponentInstantiate; class ComponentInstantiateInline; +class ComponentAliasExport; +class ComponentAliasInline; class ComponentCanonLift; class ComponentCanonLower; class ComponentCanonType; +class ComponentImport; class ComponentDeclaration { public: enum Kind : uint8_t { - CoreModuleKind, CoreInstantiateKind, - CoreInstantiateInlineKind, InstantiateKind, InstantiateInlineKind, + AliasExportKind, + AliasCoreExportKind, + AliasInlineKind, CanonLiftKind, CanonLowerKind, CanonResourceNew, CanonResourceDrop, CanonResourceRep, ImportKind, - ComponentKind, }; ComponentDeclaration(Kind kind) @@ -627,24 +637,12 @@ class ComponentDeclaration { return m_kind; } - ComponentCoreModule* asCoreModule() - { - ASSERT(kind() == CoreModuleKind); - return reinterpret_cast(this); - } - ComponentCoreInstantiate* asCoreInstantiate() { ASSERT(kind() == CoreInstantiateKind); return reinterpret_cast(this); } - ComponentCoreInstantiateInline* asCoreInstantiateInline() - { - ASSERT(kind() == CoreInstantiateInlineKind); - return reinterpret_cast(this); - } - ComponentInstantiate* asInstantiate() { ASSERT(kind() == InstantiateKind); @@ -657,6 +655,23 @@ class ComponentDeclaration { return reinterpret_cast(this); } + bool isAliasExport() + { + return kind() == AliasExportKind || kind() == AliasCoreExportKind; + } + + ComponentAliasExport* asAliasExport() + { + ASSERT(isAliasExport()); + return reinterpret_cast(this); + } + + ComponentAliasInline* asAliasInline() + { + ASSERT(kind() == AliasInlineKind); + return reinterpret_cast(this); + } + ComponentCanonLift* asCanonLift() { ASSERT(kind() == CanonLiftKind); @@ -680,25 +695,14 @@ class ComponentDeclaration { return reinterpret_cast(this); } -private: - Kind m_kind; -}; - -class ComponentCoreModule : public ComponentDeclaration { -public: - ComponentCoreModule(Module* module) - : ComponentDeclaration(CoreModuleKind) - , m_module(module) - { - } - - Module* module() + ComponentImport* asComponentImport() { - return m_module; + ASSERT(kind() == ImportKind); + return reinterpret_cast(this); } private: - Module* m_module; + Kind m_kind; }; class ComponentCoreInstantiate : public ComponentDeclaration { @@ -729,39 +733,6 @@ class ComponentCoreInstantiate : public ComponentDeclaration { std::vector m_arguments; }; -class ComponentCoreInstantiateInline : public ComponentDeclaration { -public: - struct Argument { - ComponentSort sort; - uint32_t index; - }; - - ComponentCoreInstantiateInline() - : ComponentDeclaration(CoreInstantiateInlineKind) - , m_module(nullptr) - { - } - - Module* module() - { - return m_module; - } - - void setModule(Module* module) - { - m_module = module; - } - - std::vector& arguments() - { - return m_arguments; - } - -private: - Module* m_module; - std::vector m_arguments; -}; - class ComponentInstantiate : public ComponentDeclaration { public: struct Argument { @@ -793,11 +764,6 @@ class ComponentInstantiate : public ComponentDeclaration { class ComponentInstantiateInline : public ComponentDeclaration { public: - struct Argument { - ComponentSort sort; - uint32_t index; - }; - ComponentInstantiateInline() : ComponentDeclaration(InstantiateInlineKind) { @@ -809,14 +775,70 @@ class ComponentInstantiateInline : public ComponentDeclaration { return m_type; } - std::vector& arguments() + std::vector& arguments() { return m_arguments; } private: ComponentType* m_type; - std::vector m_arguments; + std::vector m_arguments; +}; + +class ComponentAliasExport : public ComponentDeclaration { +public: + ComponentAliasExport(Kind kind, std::string name, ComponentSort sort, uint32_t instanceIndex) + : ComponentDeclaration(kind) + , m_name(name) + , m_sort(sort) + , m_instanceIndex(instanceIndex) + { + ASSERT(isAliasExport()); + } + + const std::string& name() const + { + return m_name; + } + + ComponentSort sort() const + { + return m_sort; + } + + uint32_t instanceIndex() const + { + return m_instanceIndex; + } + +private: + std::string m_name; + ComponentSort m_sort; + uint32_t m_instanceIndex; +}; + +class ComponentAliasInline : public ComponentDeclaration { +public: + ComponentAliasInline(ComponentSort sort, uint32_t exportIndex) + : ComponentDeclaration(AliasInlineKind) + , m_sort(sort) + , m_exportIndex(exportIndex) + { + } + + ComponentSort sort() const + { + return m_sort; + } + + uint32_t exportIndex() const + { + return m_exportIndex; + } + +private: + ComponentSort m_sort; + uint32_t m_exportIndex; }; class ComponentCanonLift : public ComponentDeclaration { @@ -910,19 +932,20 @@ class ComponentImport : public ComponentDeclaration { uint32_t m_importIndex; }; -class Component : public ComponentDeclaration { +class Component { friend class wabt::WASMComponentBinaryReader; public: - Component() - : ComponentDeclaration(ComponentKind) - { - m_type = new ComponentType(ComponentRefCounted::ComponentTypeKind); - } + struct InlineExport { + std::string name; + ComponentSort sort; + uint32_t index; + }; + Component(Store* store); ~Component(); - ComponentType* type() + ComponentType* type() const { return m_type; } @@ -937,10 +960,54 @@ class Component : public ComponentDeclaration { return m_declarations; } + std::vector& coreInlineExports() + { + return m_coreInlineExports; + } + + std::vector& coreInlineExportsStarts() + { + return m_coreInlineExportsStarts; + } + + size_t coreInlineExportsStart(size_t index) + { + return m_coreInlineExportsStarts[index]; + } + + size_t coreInlineExportsEnd(size_t index) + { + return m_coreInlineExportsStarts[index + 1]; + } + + void pushModule(Module* module) + { + m_modules.push_back(module); + } + + std::vector& modules() + { + return m_modules; + } + + void pushComponent(Component* component) + { + m_components.push_back(component); + } + + std::vector& components() + { + return m_components; + } + private: // Declarations for instantiation. ComponentType* m_type; std::vector m_declarations; + std::vector m_coreInlineExports; + std::vector m_coreInlineExportsStarts; + std::vector m_modules; + std::vector m_components; }; } // namespace Walrus diff --git a/src/runtime/ComponentInstance.cpp b/src/runtime/ComponentInstance.cpp new file mode 100644 index 000000000..76b3475f2 --- /dev/null +++ b/src/runtime/ComponentInstance.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2022-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. + */ +#include "Walrus.h" + +#include "runtime/ComponentInstance.h" +#include "runtime/DefinedFunctionTypes.h" +#include "runtime/Instance.h" +#include "runtime/Global.h" +#include "runtime/Memory.h" +#include "runtime/Table.h" +#include "runtime/Tag.h" +#include "runtime/Store.h" +#include "wasi/WASI02.h" + +namespace Walrus { + +DEFINE_GLOBAL_TYPE_INFO(componentInstanceTypeInfo, ComponentInstanceKind); + +LoweredFunction* LoweredFunction::createLoweredFunction(Store* store, FunctionType* functionType, LiftedFunction* liftedFunction) +{ + LoweredFunction* func = new LoweredFunction(functionType, liftedFunction); + store->appendExtern(func); + return func; +} + +void LoweredFunction::call(ExecutionState& state, Value* argv, Value* result) +{ + ASSERT(0); +} + +CanonFunction* CanonFunction::createCanonFunction(Store* store, FunctionType* functionType, Type type) +{ + CanonFunction* func = new CanonFunction(functionType, type); + store->appendExtern(func); + return func; +} + +void CanonFunction::call(ExecutionState& state, Value* argv, Value* result) +{ + ASSERT(0); +} + +void ComponentInstance::coreInstantiate(ExecutionState& state, Store* store, Component* component, ComponentCoreInstantiate* instantiate) +{ + ExternVector imports; + Module* module = component->modules()[instantiate->moduleIndex()]; + + for (auto import : module->imports()) { + Instance* instance = nullptr; + uint32_t inlineIndex = 0; + + for (auto argument : instantiate->arguments()) { + if (import->moduleName() == argument.name) { + if (argument.index < m_coreInstances.size()) { + instance = m_coreInstances[argument.index]; + } else { + inlineIndex = argument.index; + ASSERT(inlineIndex > 0); + } + break; + } + } + + Extern* value = nullptr; + + if (instance != nullptr) { + ExportType* exportType = nullptr; + for (auto field : instance->module()->exports()) { + if (import->fieldName() == field->name()) { + exportType = field; + break; + } + } + + if (exportType == nullptr) { + std::string message = "Cannot import field \""; + message.append(import->fieldName()); + message.append("\" from module: "); + message.append(import->moduleName()); + Trap::throwException(state, message); + } + + switch (import->importType()) { + case ImportType::Function: + if (exportType->exportType() == ExportType::Function) { + Function* func = instance->function(exportType->itemIndex()); + if (func->functionType()->equals(import->functionType())) { + value = func; + } + } + break; + case ImportType::Table: + if (exportType->exportType() == ExportType::Table) { + Table* table = instance->table(exportType->itemIndex()); + if (table->type() == import->tableType()->type()) { + value = table; + } + } + break; + case ImportType::Memory: + if (exportType->exportType() == ExportType::Memory) { + Memory* memory = instance->memory(exportType->itemIndex()); + if (import->memoryType()->initialSize() < memory->sizeInPageSize() + && import->memoryType()->maximumSize() >= memory->maximumSizeInPageSize() + && import->memoryType()->isShared() == memory->isShared() + && import->memoryType()->is64() == memory->is64()) { + value = memory; + } + } + break; + case ImportType::Global: + if (exportType->exportType() == ExportType::Global) { + Global* global = instance->global(exportType->itemIndex()); + if (global->type() == import->globalType()->type()) { + value = global; + } + } + break; + case ImportType::Tag: + if (exportType->exportType() == ExportType::Tag) { + Tag* tag = instance->tag(exportType->itemIndex()); + if (tag->functionType()->equals(import->tagType()->functionType())) { + value = tag; + } + } + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + } else { + if (inlineIndex == 0) { + std::string message = "Cannot import module: "; + message.append(import->moduleName()); + Trap::throwException(state, message); + } + + size_t inlineStart = component->coreInlineExportsStart(~inlineIndex); + size_t inlineEnd = component->coreInlineExportsEnd(~inlineIndex); + std::vector& exports = component->coreInlineExports(); + ComponentSort sort = ComponentSort::Invalid; + uint32_t exportIndex = 0; + + for (size_t i = inlineStart; i < inlineEnd; i++) { + if (exports[i].name == import->fieldName()) { + sort = exports[i].sort; + exportIndex = exports[i].index; + break; + } + } + + if (sort == ComponentSort::Invalid) { + std::string message = "Cannot import field \""; + message.append(import->fieldName()); + message.append("\" from module: "); + message.append(import->moduleName()); + Trap::throwException(state, message); + } + + switch (import->importType()) { + case ImportType::Function: + if (sort == ComponentSort::CoreFunc) { + Function* func = m_coreFuncs[exportIndex]; + if (func->functionType()->equals(import->functionType())) { + value = func; + } + } + break; + case ImportType::Table: + if (sort == ComponentSort::CoreTable) { + Table* table = m_coreTables[exportIndex]; + if (table->type() == import->tableType()->type()) { + value = table; + } + } + break; + case ImportType::Memory: + if (sort == ComponentSort::CoreMemory) { + Memory* memory = m_coreMemories[exportIndex]; + if (import->memoryType()->initialSize() < memory->sizeInPageSize() + && import->memoryType()->maximumSize() >= memory->maximumSizeInPageSize() + && import->memoryType()->isShared() == memory->isShared() + && import->memoryType()->is64() == memory->is64()) { + value = memory; + } + } + break; + case ImportType::Global: + if (sort == ComponentSort::CoreGlobal) { + Global* global = m_coreGlobals[exportIndex]; + if (global->type() == import->globalType()->type()) { + value = global; + } + } + break; + case ImportType::Tag: + if (sort == ComponentSort::CoreTag) { + Tag* tag = m_coreTags[exportIndex]; + if (tag->functionType()->equals(import->tagType()->functionType())) { + value = tag; + } + } + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + } + + if (value == nullptr) { + std::string message = "Type mismatch for field \""; + message.append(import->fieldName()); + message.append("\" form module: "); + message.append(import->moduleName()); + Trap::throwException(state, message); + } + + imports.push_back(value); + } + + m_coreInstances.push_back(module->instantiate(state, imports)); +} + +void ComponentInstance::aliasExport(ComponentAliasExport* alias) +{ + ComponentInstance* instance = m_instances[alias->instanceIndex()]; + + for (auto it : instance->type()->exports()) { + if (alias->name() == it.name) { + ASSERT(alias->sort() == it.sort); + switch (it.sort) { + case ComponentSort::Func: { + LiftedFunction* func = instance->m_funcs[it.exportIndex]; + m_funcs.push_back(func); + func->addRef(); + break; + } + case ComponentSort::Instance: + m_instances.push_back(instance->m_instances[it.exportIndex]); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + return; + } + } + ASSERT(0); +} + +void ComponentInstance::aliasCoreExport(ComponentAliasExport* alias) +{ + Instance* instance = m_coreInstances[alias->instanceIndex()]; + + for (auto it : instance->module()->exports()) { + if (alias->name() == it->name()) { + switch (it->exportType()) { + case ExportType::Function: + ASSERT(alias->sort() == ComponentSort::CoreFunc); + m_coreFuncs.push_back(instance->function(it->itemIndex())); + break; + case ExportType::Table: + ASSERT(alias->sort() == ComponentSort::CoreTable); + m_coreTables.push_back(instance->table(it->itemIndex())); + break; + case ExportType::Memory: + ASSERT(alias->sort() == ComponentSort::CoreMemory); + m_coreMemories.push_back(instance->memory(it->itemIndex())); + break; + case ExportType::Global: + ASSERT(alias->sort() == ComponentSort::CoreGlobal); + m_coreGlobals.push_back(instance->global(it->itemIndex())); + break; + case ExportType::Tag: + ASSERT(alias->sort() == ComponentSort::CoreTag); + m_coreTags.push_back(instance->tag(it->itemIndex())); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + return; + } + } + ASSERT(0); +} + +void ComponentInstance::aliasInline(ComponentAliasInline* alias) +{ + switch (alias->sort()) { + case ComponentSort::CoreFunc: + m_coreFuncs.push_back(m_coreFuncs[alias->exportIndex()]); + break; + case ComponentSort::CoreTable: + m_coreTables.push_back(m_coreTables[alias->exportIndex()]); + break; + case ComponentSort::CoreMemory: + m_coreMemories.push_back(m_coreMemories[alias->exportIndex()]); + break; + case ComponentSort::CoreGlobal: + m_coreGlobals.push_back(m_coreGlobals[alias->exportIndex()]); + break; + case ComponentSort::CoreTag: + m_coreTags.push_back(m_coreTags[alias->exportIndex()]); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } +} + +void ComponentInstance::lowerFunction(Store* store, ComponentCanonLower* lower) +{ +#ifdef ENABLE_WASI + LiftedFunction* func = m_funcs[lower->funcIndex()]; + m_coreFuncs.push_back(LoweredFunction::createLoweredFunction(store, func->asLiftedWasiFunction()->functionType(), func)); +#endif /* ENABLE_WASI */ +} + +ComponentInstance* ComponentInstance::instantiate(ExecutionState& state, Store* store, DefinedFunctionTypes& functionTypes, Component* component) +{ + ComponentInstance* instance = new ComponentInstance(component->type()); + + for (auto it : component->declarations()) { + switch (it->kind()) { + case ComponentDeclaration::CoreInstantiateKind: { + instance->coreInstantiate(state, store, component, it->asCoreInstantiate()); + break; + } + case ComponentDeclaration::AliasExportKind: { + instance->aliasExport(it->asAliasExport()); + break; + } + case ComponentDeclaration::AliasCoreExportKind: { + instance->aliasCoreExport(it->asAliasExport()); + break; + } + case ComponentDeclaration::AliasInlineKind: { + instance->aliasInline(it->asAliasInline()); + break; + } + case ComponentDeclaration::CanonLowerKind: { + instance->lowerFunction(store, it->asCanonLower()); + break; + } + case ComponentDeclaration::CanonResourceDrop: { + instance->m_coreFuncs.push_back(CanonFunction::createCanonFunction(store, functionTypes[DefinedFunctionTypes::I32R], CanonFunction::ResourceDrop)); + break; + } + case ComponentDeclaration::ImportKind: { + uint32_t index = it->asComponentImport()->importIndex(); + ComponentType::External& external = component->type()->imports()[index]; + bool success = false; + + switch (external.sort) { + case ComponentSort::Instance: { +#ifdef ENABLE_WASI + ComponentInstance* importedInstance = wasi02LoadInstance(external, functionTypes); + if (importedInstance != nullptr) { + store->appendComponentInstance(importedInstance); + instance->m_instances.push_back(importedInstance); + success = true; + break; + } +#endif /* ENABLE_WASI */ + break; + } + default: + break; + } + + if (!success) { + std::string message = "Cannot import: "; + message.append(external.name); + Trap::throwException(state, message); + } + break; + } + default: + // TODO: Implement more declarations. + store->appendComponentInstance(instance); + return instance; + } + } + + store->appendComponentInstance(instance); + return instance; +} + +ComponentInstance::ComponentInstance(ComponentType* type) + : Object(GET_GLOBAL_TYPE_INFO(componentInstanceTypeInfo)) + , m_type(type) +{ + type->addRef(); +} + +ComponentInstance::~ComponentInstance() +{ + m_type->releaseRef(); + for (auto it : m_funcs) { + it->releaseRef(); + } +} + +} // namespace Walrus diff --git a/src/runtime/ComponentInstance.h b/src/runtime/ComponentInstance.h new file mode 100644 index 000000000..04b277596 --- /dev/null +++ b/src/runtime/ComponentInstance.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2022-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. + */ + +#ifndef __WalrusComponentInstance__ +#define __WalrusComponentInstance__ + +#include "runtime/Component.h" +#include "runtime/Function.h" + +namespace Walrus { + +#ifdef ENABLE_WASI +class LiftedWasiFunction; +#endif /* ENABLE_WASI */ + +class LiftedFunction { +public: + enum Type { + CoreFunction, +#ifdef ENABLE_WASI + WasiFunction, +#endif /* ENABLE_WASI */ + }; + + virtual ~LiftedFunction() {} + + Type type() const + { + return m_type; + } + + void addRef() + { + m_refCount++; + } + + void releaseRef() + { + m_refCount--; + if (m_refCount == 0) { + delete this; + } + } + +#ifdef ENABLE_WASI + LiftedWasiFunction* asLiftedWasiFunction() + { + ASSERT(type() == WasiFunction); + return reinterpret_cast(this); + } +#endif /* ENABLE_WASI */ + +protected: + LiftedFunction(Type type) + : m_type(type) + , m_refCount(1) + { + } + +private: + Type m_type; + size_t m_refCount; +}; + +#ifdef ENABLE_WASI + +class LiftedWasiFunction : public LiftedFunction { +public: + enum Type { + cliExit026, + ioPollableBlock026, + ioOutputStreamCheckWrite026, + ioOutputStreamWrite026, + ioOutputStreamBlockingWriteAndFlush026, + ioOutputStreamBlockingFlush026, + ioOutputStreamSubscribe026, + cliGetStdin026, + cliGetStdout026, + cliGetStderr026, + cliGetTerminalStdin026, + cliGetTerminalStdout026, + cliGetTerminalStderr026, + }; + + LiftedWasiFunction(Type type, FunctionType* functionType) + : LiftedFunction(WasiFunction) + , m_type(type) + , m_functionType(functionType) + { + } + + FunctionType* functionType() const + { + return m_functionType; + } + +private: + Type m_type; + FunctionType* m_functionType; +}; + +#endif /* ENABLE_WASI */ + +class LoweredFunction : public NativeFunction { +public: + static LoweredFunction* createLoweredFunction(Store* store, FunctionType* functionType, LiftedFunction* liftedFunction); + + virtual void call(ExecutionState& state, Value* argv, Value* result) override; + +private: + LoweredFunction(FunctionType* functionType, LiftedFunction* liftedFunction) + : NativeFunction(functionType) + , m_liftedFunction(liftedFunction) + { + } + + LiftedFunction* m_liftedFunction; +}; + +class CanonFunction : public NativeFunction { +public: + enum Type { + ResourceNew, + ResourceDrop, + ResourceRep, + }; + + static CanonFunction* createCanonFunction(Store* store, FunctionType* functionType, Type type); + + Type type() const + { + return m_type; + } + + virtual void call(ExecutionState& state, Value* argv, Value* result) override; + +private: + CanonFunction(FunctionType* functionType, Type type) + : NativeFunction(functionType) + , m_type(type) + { + } + + Type m_type; +}; + +class DefinedFunctionTypes; + +class ComponentInstance : public Object { +#ifdef ENABLE_WASI + friend class ComponentInstanceWasi02; +#endif /* ENABLE_WASI */ + +public: + static ComponentInstance* instantiate(ExecutionState& state, Store* store, DefinedFunctionTypes& functionTypes, Component* component); + + ~ComponentInstance(); + + ComponentType* type() + { + return m_type; + } + +private: + ComponentInstance(ComponentType* type); + + void coreInstantiate(ExecutionState& state, Store* store, Component* component, ComponentCoreInstantiate* instantiate); + void aliasExport(ComponentAliasExport* alias); + void aliasCoreExport(ComponentAliasExport* alias); + void aliasInline(ComponentAliasInline* alias); + void lowerFunction(Store* store, ComponentCanonLower* lower); + + ComponentType* m_type; + std::vector m_coreFuncs; + std::vector m_coreTables; + std::vector m_coreMemories; + std::vector m_coreGlobals; + std::vector m_coreTags; + std::vector m_coreInstances; + std::vector m_funcs; + std::vector m_instances; +}; + +} // namespace Walrus + +#endif // __WalrusComponentInstance__ diff --git a/src/runtime/DefinedFunctionTypes.h b/src/runtime/DefinedFunctionTypes.h index a552ed68c..683d82f09 100644 --- a/src/runtime/DefinedFunctionTypes.h +++ b/src/runtime/DefinedFunctionTypes.h @@ -29,6 +29,8 @@ class DefinedFunctionTypes { // The R is meant to represent the results, after R are the result types. NONE = 0, I32R, + I32I32R, + I32I32I32I32R, I32_RI32, I32I32_RI32, I32I64I32_RI32, @@ -74,6 +76,26 @@ class DefinedFunctionTypes { functionType->initDone(); m_vector[index++] = functionType; } + { + // I32I32R + functionType = new FunctionType(2, 0, 0, 0); + param = functionType->initParam(); + param->setType(0, Value::Type::I32); + param->setType(1, Value::Type::I32); + functionType->initDone(); + m_vector[index++] = functionType; + } + { + // I32I32I32I32R + functionType = new FunctionType(4, 0, 0, 0); + param = functionType->initParam(); + param->setType(0, Value::Type::I32); + param->setType(1, Value::Type::I32); + param->setType(2, Value::Type::I32); + param->setType(3, Value::Type::I32); + functionType->initDone(); + m_vector[index++] = functionType; + } { // I32_RI32 functionType = new FunctionType(1, 0, 1, 0); diff --git a/src/runtime/Function.cpp b/src/runtime/Function.cpp index 92980c724..0460da1e6 100644 --- a/src/runtime/Function.cpp +++ b/src/runtime/Function.cpp @@ -112,20 +112,8 @@ void DefinedFunctionWithTryCatch::interpreterCall(ExecutionState& state, uint8_t Interpreter::callInterpreter(state, this, bp, offsets, parameterOffsetCount, resultOffsetCount); } -ImportedFunction* ImportedFunction::createImportedFunction(Store* store, - FunctionType* functionType, - ImportedFunctionCallback callback, - void* data) -{ - ImportedFunction* func = new ImportedFunction(functionType, - callback, - data); - store->appendExtern(func); - return func; -} - -void ImportedFunction::interpreterCall(ExecutionState& state, uint8_t* bp, ByteCodeStackOffset* offsets, - uint16_t parameterOffsetCount, uint16_t resultOffsetCount) +void NativeFunction::interpreterCall(ExecutionState& state, uint8_t* bp, ByteCodeStackOffset* offsets, + uint16_t parameterOffsetCount, uint16_t resultOffsetCount) { const FunctionType* ft = functionType(); const TypeVector::Types& paramTypeInfo = ft->param().types(); @@ -150,6 +138,18 @@ void ImportedFunction::interpreterCall(ExecutionState& state, uint8_t* bp, ByteC } } +ImportedFunction* ImportedFunction::createImportedFunction(Store* store, + FunctionType* functionType, + ImportedFunctionCallback callback, + void* data) +{ + ImportedFunction* func = new ImportedFunction(functionType, + callback, + data); + store->appendExtern(func); + return func; +} + void ImportedFunction::call(ExecutionState& state, Value* argv, Value* result) { ExecutionState newState(state, this); @@ -167,32 +167,6 @@ WasiFunction* WasiFunction::createWasiFunction(Store* store, return func; } -void WasiFunction::interpreterCall(ExecutionState& state, uint8_t* bp, ByteCodeStackOffset* offsets, - uint16_t parameterOffsetCount, uint16_t resultOffsetCount) -{ - const FunctionType* ft = functionType(); - const TypeVector::Types& paramTypeInfo = ft->param().types(); - const TypeVector::Types& resultTypeInfo = ft->result().types(); - - 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); diff --git a/src/runtime/Function.h b/src/runtime/Function.h index 2535895ff..95592e134 100644 --- a/src/runtime/Function.h +++ b/src/runtime/Function.h @@ -43,6 +43,7 @@ class FunctionType; class ModuleFunction; class DefinedFunction; class ImportedFunction; +class LoweredFunction; class WasiFunction; class Function : public Extern { @@ -58,6 +59,7 @@ class Function : public Extern { { return false; } + virtual bool isImportedFunction() const { return false; @@ -74,12 +76,6 @@ class Function : public Extern { return reinterpret_cast(this); } - ImportedFunction* asImportedFunction() - { - ASSERT(isImportedFunction()); - return reinterpret_cast(this); - } - WasiFunction* asWasiFunction() { ASSERT(isWasiFunction()); @@ -92,7 +88,6 @@ class Function : public Extern { const FunctionType* m_functionType; }; - class DefinedFunction : public Function { friend class Module; @@ -137,7 +132,19 @@ class DefinedFunctionWithTryCatch : public DefinedFunction { } }; -class ImportedFunction : public Function { +class NativeFunction : public Function { +public: + virtual void interpreterCall(ExecutionState& state, uint8_t* bp, ByteCodeStackOffset* offsets, + uint16_t parameterOffsetCount, uint16_t resultOffsetCount) override; + +protected: + NativeFunction(FunctionType* functionType) + : Function(functionType) + { + } +}; + +class ImportedFunction : public NativeFunction { public: typedef std::function ImportedFunctionCallback; @@ -146,19 +153,13 @@ class ImportedFunction : public Function { ImportedFunctionCallback callback, void* data); - virtual bool isImportedFunction() const override - { - return true; - } 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: ImportedFunction(FunctionType* functionType, ImportedFunctionCallback callback, void* data) - : Function(functionType) + : NativeFunction(functionType) , m_callback(callback) , m_data(data) { @@ -168,7 +169,7 @@ class ImportedFunction : public Function { void* m_data; }; -class WasiFunction : public Function { +class WasiFunction : public NativeFunction { public: typedef std::function WasiFunctionCallback; @@ -187,13 +188,11 @@ class WasiFunction : public Function { } 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) - : Function(functionType) + : NativeFunction(functionType) , m_callback(callback) , m_runningInstance(nullptr) { diff --git a/src/runtime/Instance.h b/src/runtime/Instance.h index 64e0680d4..77e1529dd 100644 --- a/src/runtime/Instance.h +++ b/src/runtime/Instance.h @@ -112,15 +112,35 @@ class Instance : public Object { Module* module() const { return m_module; } - Function* function(uint32_t index) const { return m_functions[index]; } + Function* function(uint32_t index) const + { + ASSERT(index < module()->numberOfFunctions()); + return m_functions[index]; + } + + Table* table(uint32_t index) const + { + ASSERT(index < module()->numberOfTableTypes()); + return m_tables[index]; + } + Memory* memory(uint32_t index) const { ASSERT(index < module()->numberOfMemoryTypes()); return m_memories[index]; } - Table* table(uint32_t index) const { return m_tables[index]; } - Tag* tag(uint32_t index) const { return m_tags[index]; } - Global* global(uint32_t index) const { return m_globals[index]; } + + Global* global(uint32_t index) const + { + ASSERT(index < module()->numberOfGlobalTypes()); + return m_globals[index]; + } + + Tag* tag(uint32_t index) const + { + ASSERT(index < module()->numberOfTagTypes()); + return m_tags[index]; + } DataSegment* dataSegment(uint32_t index) { return m_dataSegments + index; } ElementSegment* elementSegment(uint32_t index) { return m_elementSegments + index; } diff --git a/src/runtime/Module.cpp b/src/runtime/Module.cpp index 8163c4113..9fb9fae5b 100644 --- a/src/runtime/Module.cpp +++ b/src/runtime/Module.cpp @@ -210,7 +210,9 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports case ImportType::Memory: { if (UNLIKELY(imports[i]->kind() != Object::MemoryKind || m_imports[i]->memoryType()->initialSize() > imports[i]->asMemory()->sizeInPageSize() - || m_imports[i]->memoryType()->maximumSize() < imports[i]->asMemory()->maximumSizeInPageSize())) { + || m_imports[i]->memoryType()->maximumSize() < imports[i]->asMemory()->maximumSizeInPageSize() + || m_imports[i]->memoryType()->isShared() != imports[i]->asMemory()->isShared() + || m_imports[i]->memoryType()->is64() != imports[i]->asMemory()->is64())) { Trap::throwException(state, "incompatible import type"); } @@ -218,7 +220,8 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports break; } case ImportType::Tag: { - if (UNLIKELY(imports[i]->kind() != Object::TagKind)) { + if (UNLIKELY(imports[i]->kind() != Object::TagKind + || !imports[i]->asTag()->functionType()->equals(m_imports[i]->tagType()->functionType(), true))) { Trap::throwException(state, "incompatible import type"); } instance->m_tags[tagIndex++] = imports[i]->asTag(); @@ -274,7 +277,7 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports // init tag while (tagIndex < m_tagTypes.size()) { - instance->m_tags[tagIndex] = Tag::createTag(m_store, m_compositeTypes[m_tagTypes[tagIndex]->sigIndex()]->asFunction()); + instance->m_tags[tagIndex] = Tag::createTag(m_store, m_tagTypes[tagIndex]->functionType()); tagIndex++; } diff --git a/src/runtime/Module.h b/src/runtime/Module.h index d4bb45cc3..8158a35f9 100644 --- a/src/runtime/Module.h +++ b/src/runtime/Module.h @@ -132,6 +132,12 @@ class ImportType { return static_cast(m_type); } + const TagType* tagType() const + { + ASSERT(importType() == Type::Tag); + return static_cast(m_type); + } + std::string typeToString() { switch (m_importType) { diff --git a/src/runtime/Object.h b/src/runtime/Object.h index e691ec89d..46f141641 100644 --- a/src/runtime/Object.h +++ b/src/runtime/Object.h @@ -49,6 +49,9 @@ class Object { MemoryKind, TrapKind, TagKind, + // Component types + LiftedFunctionKind, + ComponentInstanceKind, // Used by the test system ExternalValueKind, Invalid, diff --git a/src/runtime/ObjectType.h b/src/runtime/ObjectType.h index 796ae1c1e..6e1b3676e 100644 --- a/src/runtime/ObjectType.h +++ b/src/runtime/ObjectType.h @@ -347,16 +347,16 @@ class MemoryType : public ObjectType { class TagType : public ObjectType { public: - TagType(uint32_t sigIndex) + TagType(const FunctionType* functionType) : ObjectType(ObjectType::TagKind) - , m_sigIndex(sigIndex) + , m_functionType(functionType) { } - uint32_t sigIndex() const { return m_sigIndex; } + const FunctionType* functionType() const { return m_functionType; } private: - uint32_t m_sigIndex; + const FunctionType* m_functionType; }; // ObjectType Vectors diff --git a/src/runtime/Store.cpp b/src/runtime/Store.cpp index ed4cbdfe8..bdd9750f2 100644 --- a/src/runtime/Store.cpp +++ b/src/runtime/Store.cpp @@ -18,6 +18,8 @@ #include "runtime/Store.h" #include "runtime/Module.h" #include "runtime/Instance.h" +#include "runtime/Component.h" +#include "runtime/ComponentInstance.h" #include "runtime/ObjectType.h" #ifdef ENABLE_GC @@ -56,6 +58,14 @@ Store::~Store() delete m_modules[i]; } + for (size_t i = 0; i < m_componentInstances.size(); i++) { + delete m_componentInstances[i]; + } + + for (size_t i = 0; i < m_components.size(); i++) { + delete m_components[i]; + } + for (size_t i = 0; i < m_externs.size(); i++) { delete m_externs[i]; } diff --git a/src/runtime/Store.h b/src/runtime/Store.h index 9bd7ac801..f8ccef400 100644 --- a/src/runtime/Store.h +++ b/src/runtime/Store.h @@ -28,6 +28,8 @@ namespace Walrus { class Engine; class Module; class Instance; +class Component; +class ComponentInstance; class Extern; class FunctionType; @@ -71,6 +73,16 @@ class Store { m_instances.push_back(instance); } + void appendComponent(Component* component) + { + m_components.push_back(component); + } + + void appendComponentInstance(ComponentInstance* instance) + { + m_componentInstances.push_back(instance); + } + void appendExtern(Extern* ext) { m_externs.push_back(ext); @@ -95,6 +107,8 @@ class Store { Vector m_modules; Vector m_instances; + Vector m_components; + Vector m_componentInstances; Vector m_externs; std::mutex m_waiterListLock; diff --git a/src/runtime/Tag.cpp b/src/runtime/Tag.cpp index a7a3bbe40..c7c5e184d 100644 --- a/src/runtime/Tag.cpp +++ b/src/runtime/Tag.cpp @@ -21,7 +21,7 @@ namespace Walrus { DEFINE_GLOBAL_TYPE_INFO(tagTypeInfo, TagKind); -Tag::Tag(FunctionType* functionType) +Tag::Tag(const FunctionType* functionType) : Extern(GET_GLOBAL_TYPE_INFO(tagTypeInfo)) , m_functionType(functionType) { diff --git a/src/runtime/Tag.h b/src/runtime/Tag.h index b4808ca39..4888bd13e 100644 --- a/src/runtime/Tag.h +++ b/src/runtime/Tag.h @@ -26,7 +26,7 @@ class FunctionType; class Tag : public Extern { public: - static Tag* createTag(Store* store, FunctionType* functionType) + static Tag* createTag(Store* store, const FunctionType* functionType) { Tag* tag = new Tag(functionType); store->appendExtern(tag); @@ -39,7 +39,7 @@ class Tag : public Extern { } private: - Tag(FunctionType* functionType); + Tag(const FunctionType* functionType); const FunctionType* m_functionType; }; diff --git a/src/shell/Shell.cpp b/src/shell/Shell.cpp index a817db9fd..16e2e09f2 100644 --- a/src/shell/Shell.cpp +++ b/src/shell/Shell.cpp @@ -12,7 +12,7 @@ #include "runtime/Engine.h" #include "runtime/Store.h" #include "runtime/Module.h" -#include "runtime/Component.h" +#include "runtime/ComponentInstance.h" #include "runtime/Instance.h" #include "runtime/Function.h" #include "runtime/Table.h" @@ -370,15 +370,27 @@ static Trap::TrapResult executeWASM(Store* store, const std::string& filename, c &data); } -static wabt::Result executeWASMComponent(Store* store, const std::string& filename, const std::vector& src) +static Trap::TrapResult executeWASMComponent(Store* store, DefinedFunctionTypes& functionTypes, const std::string& filename, const std::vector& src) { std::pair, std::string> parseResult = WASMComponentParser::parseBinary(store, filename, src.data(), src.size()); if (!parseResult.second.empty()) { - printf("Cannot run module: %s\n", parseResult.second.c_str()); - return wabt::Result::Error; + Trap::TrapResult tr; + tr.exception = Exception::create(parseResult.second); + return tr; } - return wabt::Result::Ok; + struct RunData { + Component* component; + Store* store; + DefinedFunctionTypes& functionTypes; + } data = { parseResult.first.value(), store, functionTypes }; + + Walrus::Trap trap; + return trap.run([](ExecutionState& state, void* d) { + RunData* data = reinterpret_cast(d); + ComponentInstance* instance = ComponentInstance::instantiate(state, data->store, data->functionTypes, data->component); + }, + &data); } static bool endsWith(const std::string& str, const std::string& suffix) @@ -831,7 +843,11 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve result = WriteBinaryComponent(&stream, component.get(), writeBinaryOptions); if (wabt::Succeeded(result)) { - result = executeWASMComponent(store, filename, stream.output_buffer().data); + auto trapResult = executeWASMComponent(store, functionTypes, filename, stream.output_buffer().data); + if (trapResult.exception) { + std::string& errorMessage = trapResult.exception->message(); + printf("Error: %s\n", errorMessage.c_str()); + } } } @@ -1327,7 +1343,11 @@ int main(int argc, const char* argv[]) if (!options.exportToRun.empty()) { runExports(store, filePath, buf, options.exportToRun, functionTypes); } else if (wabt::ReadBinaryIsComponent(buf.data(), buf.size())) { - executeWASMComponent(store, filePath, buf); + auto trapResult = executeWASMComponent(store, functionTypes, filePath, buf); + if (trapResult.exception) { + fprintf(stderr, "Uncaught Exception: %s\n", trapResult.exception->message().data()); + return -1; + } } else { auto trapResult = executeWASM(store, filePath, buf, functionTypes); if (trapResult.exception) { diff --git a/src/wasi/WASI02.cpp b/src/wasi/WASI02.cpp new file mode 100644 index 000000000..2e6106f9b --- /dev/null +++ b/src/wasi/WASI02.cpp @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#ifdef ENABLE_WASI + +#include "wasi/WASI02.h" +#include "runtime/ComponentInstance.h" +#include "runtime/DefinedFunctionTypes.h" + +namespace Walrus { + +class ComponentInstanceWasi02 { +public: + static void addExport(ComponentInstance* instance, const char* name, LiftedWasiFunction::Type type, FunctionType* functionType); + static ComponentInstance* loadInstance(ComponentType::External& external, DefinedFunctionTypes& functionTypes); +}; + +void ComponentInstanceWasi02::addExport(ComponentInstance* instance, const char* name, LiftedWasiFunction::Type type, FunctionType* functionType) +{ + instance->m_type->exports().push_back(ComponentType::External{ name, nullptr, ComponentSort::Func, static_cast(instance->m_funcs.size()) }); + instance->m_funcs.push_back(new LiftedWasiFunction(type, functionType)); +} + +ComponentInstance* ComponentInstanceWasi02::loadInstance(ComponentType::External& external, DefinedFunctionTypes& functionTypes) +{ + if (external.name == "wasi:cli/exit@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "exit", LiftedWasiFunction::cliExit026, functionTypes[DefinedFunctionTypes::I32R]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:io/error@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:io/poll@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "[method]pollable.block", LiftedWasiFunction::ioPollableBlock026, functionTypes[DefinedFunctionTypes::I32R]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:io/streams@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "[method]output-stream.check-write", LiftedWasiFunction::ioOutputStreamCheckWrite026, functionTypes[DefinedFunctionTypes::I32I32R]); + addExport(instance, "[method]output-stream.write", LiftedWasiFunction::ioOutputStreamWrite026, functionTypes[DefinedFunctionTypes::I32I32I32I32R]); + addExport(instance, "[method]output-stream.blocking-write-and-flush", LiftedWasiFunction::ioOutputStreamBlockingWriteAndFlush026, functionTypes[DefinedFunctionTypes::I32I32I32I32R]); + addExport(instance, "[method]output-stream.blocking-flush", LiftedWasiFunction::ioOutputStreamBlockingFlush026, functionTypes[DefinedFunctionTypes::I32I32R]); + addExport(instance, "[method]output-stream.subscribe", LiftedWasiFunction::ioOutputStreamSubscribe026, functionTypes[DefinedFunctionTypes::I32_RI32]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/stdin@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "get-stdin", LiftedWasiFunction::cliGetStdin026, functionTypes[DefinedFunctionTypes::RI32]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/stdout@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "get-stdout", LiftedWasiFunction::cliGetStdout026, functionTypes[DefinedFunctionTypes::RI32]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/stderr@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "get-stderr", LiftedWasiFunction::cliGetStderr026, functionTypes[DefinedFunctionTypes::RI32]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/terminal-input@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/terminal-output@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/terminal-stdin@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "get-terminal-stdin", LiftedWasiFunction::cliGetTerminalStdin026, functionTypes[DefinedFunctionTypes::I32R]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/terminal-stdout@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "get-terminal-stdout", LiftedWasiFunction::cliGetTerminalStdout026, functionTypes[DefinedFunctionTypes::I32R]); + type->releaseRef(); + return instance; + } + if (external.name == "wasi:cli/terminal-stderr@0.2.6") { + ComponentType* type = new ComponentType(ComponentType::ComponentTypeKind); + ComponentInstance* instance = new ComponentInstance(type); + addExport(instance, "get-terminal-stderr", LiftedWasiFunction::cliGetTerminalStderr026, functionTypes[DefinedFunctionTypes::I32R]); + type->releaseRef(); + return instance; + } + return nullptr; +} + +ComponentInstance* wasi02LoadInstance(ComponentType::External& external, DefinedFunctionTypes& functionTypes) +{ + return ComponentInstanceWasi02::loadInstance(external, functionTypes); +} + +} // namespace Walrus + +#endif diff --git a/src/wasi/WASI02.h b/src/wasi/WASI02.h new file mode 100644 index 000000000..a63ce8b12 --- /dev/null +++ b/src/wasi/WASI02.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef __WalrusWASI02__ +#define __WalrusWASI02__ + +#ifdef ENABLE_WASI + +#include "Walrus.h" +#include "runtime/Component.h" + +namespace Walrus { + +class ComponentInstance; +class DefinedFunctionTypes; + +ComponentInstance* wasi02LoadInstance(ComponentType::External& external, DefinedFunctionTypes& functionTypes); + +} // namespace Walrus + +#endif + +#endif // __WalrusWASI02__