diff options
60 files changed, 2011 insertions, 720 deletions
diff --git a/build-js.sh b/build-js.sh index 71bed923e..832847f74 100755 --- a/build-js.sh +++ b/build-js.sh @@ -230,6 +230,7 @@ export_function "_BinaryenExternalFunction" export_function "_BinaryenExternalTable" export_function "_BinaryenExternalMemory" export_function "_BinaryenExternalGlobal" +export_function "_BinaryenExternalEvent" # Features export_function "_BinaryenFeatureMVP" @@ -759,14 +760,19 @@ export_function "_BinaryenRemoveFunction" export_function "_BinaryenAddGlobal" export_function "_BinaryenGetGlobal" export_function "_BinaryenRemoveGlobal" +export_function "_BinaryenAddEvent" +export_function "_BinaryenGetEvent" +export_function "_BinaryenRemoveEvent" export_function "_BinaryenAddFunctionImport" export_function "_BinaryenAddTableImport" export_function "_BinaryenAddMemoryImport" export_function "_BinaryenAddGlobalImport" +export_function "_BinaryenAddEventImport" export_function "_BinaryenAddFunctionExport" export_function "_BinaryenAddTableExport" export_function "_BinaryenAddMemoryExport" export_function "_BinaryenAddGlobalExport" +export_function "_BinaryenAddEventExport" export_function "_BinaryenRemoveExport" export_function "_BinaryenSetFunctionTable" export_function "_BinaryenSetMemory" @@ -817,11 +823,20 @@ export_function "_BinaryenGlobalGetType" export_function "_BinaryenGlobalIsMutable" export_function "_BinaryenGlobalGetInitExpr" +# 'Event' operations +export_function "_BinaryenEventGetName" +export_function "_BinaryenEventGetType" +export_function "_BinaryenEventGetNumParams" +export_function "_BinaryenEventGetParam" +export_function "_BinaryenEventGetAttribute" + # 'Import' operations export_function "_BinaryenGlobalImportGetModule" export_function "_BinaryenGlobalImportGetBase" export_function "_BinaryenFunctionImportGetModule" export_function "_BinaryenFunctionImportGetBase" +export_function "_BinaryenEventImportGetModule" +export_function "_BinaryenEventImportGetBase" # 'Export' operations export_function "_BinaryenExportGetKind" diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index da3485843..2df1d478a 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -125,6 +125,7 @@ std::map<BinaryenFunctionTypeRef, size_t> functionTypes; std::map<BinaryenExpressionRef, size_t> expressions; std::map<BinaryenFunctionRef, size_t> functions; std::map<BinaryenGlobalRef, size_t> globals; +std::map<BinaryenEventRef, size_t> events; std::map<BinaryenExportRef, size_t> exports; std::map<RelooperBlockRef, size_t> relooperBlocks; @@ -368,6 +369,9 @@ BinaryenExternalKind BinaryenExternalMemory(void) { BinaryenExternalKind BinaryenExternalGlobal(void) { return static_cast<BinaryenExternalKind>(ExternalKind::Global); } +BinaryenExternalKind BinaryenExternalEvent(void) { + return static_cast<BinaryenExternalKind>(ExternalKind::Event); +} // Features @@ -417,12 +421,14 @@ void BinaryenModuleDispose(BinaryenModuleRef module) { std::cout << " expressions.clear();\n"; std::cout << " functions.clear();\n"; std::cout << " globals.clear();\n"; + std::cout << " events.clear();\n"; std::cout << " exports.clear();\n"; std::cout << " relooperBlocks.clear();\n"; functionTypes.clear(); expressions.clear(); functions.clear(); globals.clear(); + events.clear(); exports.clear(); relooperBlocks.clear(); } @@ -2775,6 +2781,45 @@ void BinaryenRemoveGlobal(BinaryenModuleRef module, const char* name) { wasm->removeGlobal(name); } +// Events + +BinaryenEventRef BinaryenAddEvent(BinaryenModuleRef module, + const char* name, + uint32_t attribute, + BinaryenFunctionTypeRef type) { + if (tracing) { + std::cout << " BinaryenAddEvent(the_module, \"" << name << "\", " + << attribute << ", functionTypes[" << functionTypes[type] + << "]);\n"; + } + + auto* wasm = (Module*)module; + auto* ret = new Event(); + ret->name = name; + ret->attribute = attribute; + ret->type = ((FunctionType*)type)->name; + ret->params = ((FunctionType*)type)->params; + wasm->addEvent(ret); + return ret; +} + +BinaryenEventRef BinaryenGetEvent(BinaryenModuleRef module, const char* name) { + if (tracing) { + std::cout << " BinaryenGetEvent(the_module, \"" << name << "\");\n"; + } + + auto* wasm = (Module*)module; + return wasm->getEvent(name); +} +void BinaryenRemoveEvent(BinaryenModuleRef module, const char* name) { + if (tracing) { + std::cout << " BinaryenRemoveEvent(the_module, \"" << name << "\");\n"; + } + + auto* wasm = (Module*)module; + wasm->removeEvent(name); +} + // Imports void BinaryenAddFunctionImport(BinaryenModuleRef module, @@ -2850,6 +2895,29 @@ void BinaryenAddGlobalImport(BinaryenModuleRef module, ret->type = Type(globalType); wasm->addGlobal(ret); } +void BinaryenAddEventImport(BinaryenModuleRef module, + const char* internalName, + const char* externalModuleName, + const char* externalBaseName, + uint32_t attribute, + BinaryenFunctionTypeRef eventType) { + auto* wasm = (Module*)module; + auto* ret = new Event(); + + if (tracing) { + std::cout << " BinaryenAddEventImport(the_module, \"" << internalName + << "\", \"" << externalModuleName << "\", \"" << externalBaseName + << "\", " << attribute << ", functionTypes[" + << functionTypes[eventType] << "]);\n"; + } + + ret->name = internalName; + ret->module = externalModuleName; + ret->base = externalBaseName; + ret->type = ((FunctionType*)eventType)->name; + ret->params = ((FunctionType*)eventType)->params; + wasm->addEvent(ret); +} // Exports @@ -2938,6 +3006,26 @@ BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module, wasm->addExport(ret); return ret; } +BinaryenExportRef BinaryenAddEventExport(BinaryenModuleRef module, + const char* internalName, + const char* externalName) { + auto* wasm = (Module*)module; + auto* ret = new Export(); + + if (tracing) { + auto id = exports.size(); + exports[ret] = id; + std::cout << " exports[" << id + << "] = BinaryenAddEventExport(the_module, \"" << internalName + << "\", \"" << externalName << "\");\n"; + } + + ret->value = internalName; + ret->name = externalName; + ret->kind = ExternalKind::Event; + wasm->addExport(ret); + return ret; +} void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) { if (tracing) { std::cout << " BinaryenRemoveExport(the_module, \"" << externalName @@ -3655,6 +3743,52 @@ BinaryenExpressionRef BinaryenGlobalGetInitExpr(BinaryenGlobalRef global) { } // +// =========== Event operations =========== +// + +const char* BinaryenEventGetName(BinaryenEventRef event) { + if (tracing) { + std::cout << " BinaryenEventGetName(events[" << events[event] << "]);\n"; + } + + return ((Event*)event)->name.c_str(); +} +int BinaryenEventGetAttribute(BinaryenEventRef event) { + if (tracing) { + std::cout << " BinaryenEventGetAttribute(events[" << events[event] + << "]);\n"; + } + + return ((Event*)event)->attribute; +} +const char* BinaryenEventGetType(BinaryenEventRef event) { + if (tracing) { + std::cout << " BinaryenEventGetType(events[" << events[event] << "]);\n"; + } + + return ((Event*)event)->type.c_str(); +} +BinaryenIndex BinaryenEventGetNumParams(BinaryenEventRef event) { + if (tracing) { + std::cout << " BinaryenEventGetNumParams(events[" << events[event] + << "]);\n"; + } + + return ((Event*)event)->params.size(); +} +BinaryenType BinaryenEventGetParam(BinaryenEventRef event, + BinaryenIndex index) { + if (tracing) { + std::cout << " BinaryenEventGetParam(events[" << events[event] << "], " + << index << ");\n"; + } + + auto* fn = (Event*)event; + assert(index < fn->params.size()); + return fn->params[index]; +} + +// // =========== Import operations =========== // @@ -3684,6 +3818,19 @@ const char* BinaryenGlobalImportGetModule(BinaryenGlobalRef import) { return ""; } } +const char* BinaryenEventImportGetModule(BinaryenEventRef import) { + if (tracing) { + std::cout << " BinaryenEventImportGetModule(events[" << events[import] + << "]);\n"; + } + + auto* event = (Event*)import; + if (event->imported()) { + return event->module.c_str(); + } else { + return ""; + } +} const char* BinaryenFunctionImportGetBase(BinaryenFunctionRef import) { if (tracing) { std::cout << " BinaryenFunctionImportGetBase(functions[" @@ -3710,6 +3857,19 @@ const char* BinaryenGlobalImportGetBase(BinaryenGlobalRef import) { return ""; } } +const char* BinaryenEventImportGetBase(BinaryenEventRef import) { + if (tracing) { + std::cout << " BinaryenEventImportGetBase(events[" << events[import] + << "]);\n"; + } + + auto* event = (Event*)import; + if (event->imported()) { + return event->base.c_str(); + } else { + return ""; + } +} // // =========== Export operations =========== @@ -3875,6 +4035,7 @@ void BinaryenSetAPITracing(int on) { " std::map<size_t, BinaryenExpressionRef> expressions;\n" " std::map<size_t, BinaryenFunctionRef> functions;\n" " std::map<size_t, BinaryenGlobalRef> globals;\n" + " std::map<size_t, BinaryenEventRef> events;\n" " std::map<size_t, BinaryenExportRef> exports;\n" " std::map<size_t, RelooperBlockRef> relooperBlocks;\n" " BinaryenModuleRef the_module = NULL;\n" diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 879d78498..7b9b0141a 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -136,6 +136,7 @@ BinaryenExternalKind BinaryenExternalFunction(void); BinaryenExternalKind BinaryenExternalTable(void); BinaryenExternalKind BinaryenExternalMemory(void); BinaryenExternalKind BinaryenExternalGlobal(void); +BinaryenExternalKind BinaryenExternalEvent(void); // Features. Call to get the value of each; you can cache them. Use bitwise // operators to combine and test particular features. @@ -882,6 +883,12 @@ void BinaryenAddGlobalImport(BinaryenModuleRef module, const char* externalModuleName, const char* externalBaseName, BinaryenType globalType); +void BinaryenAddEventImport(BinaryenModuleRef module, + const char* internalName, + const char* externalModuleName, + const char* externalBaseName, + uint32_t attribute, + BinaryenFunctionTypeRef eventType); // Exports @@ -902,6 +909,9 @@ BinaryenExportRef BinaryenAddMemoryExport(BinaryenModuleRef module, BinaryenExportRef BinaryenAddGlobalExport(BinaryenModuleRef module, const char* internalName, const char* externalName); +BinaryenExportRef BinaryenAddEventExport(BinaryenModuleRef module, + const char* internalName, + const char* externalName); void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName); // Globals @@ -917,6 +927,17 @@ BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module, BinaryenGlobalRef BinaryenGetGlobal(BinaryenModuleRef module, const char* name); void BinaryenRemoveGlobal(BinaryenModuleRef module, const char* name); +// Events + +typedef void* BinaryenEventRef; + +BinaryenEventRef BinaryenAddEvent(BinaryenModuleRef module, + const char* name, + uint32_t attribute, + BinaryenFunctionTypeRef type); +BinaryenEventRef BinaryenGetEvent(BinaryenModuleRef module, const char* name); +void BinaryenEventEvent(BinaryenModuleRef module, const char* name); + // Function table. One per module void BinaryenSetFunctionTable(BinaryenModuleRef module, @@ -1153,6 +1174,21 @@ int BinaryenGlobalIsMutable(BinaryenGlobalRef global); BinaryenExpressionRef BinaryenGlobalGetInitExpr(BinaryenGlobalRef global); // +// ========== Event Operations ========== +// + +// Gets the name of the specified `Event`. +const char* BinaryenEventGetName(BinaryenEventRef event); +// Gets the attribute of the specified `Event`. +int BinaryenEventGetAttribute(BinaryenEventRef event); +// Gets the name of the `FunctionType` associated with the specified `Event`. +const char* BinaryenEventGetType(BinaryenEventRef event); +// Gets the number of parameters of the specified `Event`. +BinaryenIndex BinaryenEventGetNumParams(BinaryenEventRef event); +// Gets the type of the parameter at the specified index of the specified +// `Event`. +BinaryenType BinaryenEventGetParam(BinaryenEventRef event, BinaryenIndex index); + // // ========== Import Operations ========== // @@ -1160,9 +1196,11 @@ BinaryenExpressionRef BinaryenGlobalGetInitExpr(BinaryenGlobalRef global); // Gets the external module name of the specified import. const char* BinaryenFunctionImportGetModule(BinaryenFunctionRef import); const char* BinaryenGlobalImportGetModule(BinaryenGlobalRef import); +const char* BinaryenEventImportGetModule(BinaryenEventRef import); // Gets the external base name of the specified import. const char* BinaryenFunctionImportGetBase(BinaryenFunctionRef import); const char* BinaryenGlobalImportGetBase(BinaryenGlobalRef import); +const char* BinaryenEventImportGetBase(BinaryenEventRef import); // // ========== Export Operations ========== diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 0bd8a7a0f..6723c5e4f 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -172,6 +172,7 @@ void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE(); } void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE(); } void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE(); } void ReFinalize::visitMemory(Memory* curr) { WASM_UNREACHABLE(); } +void ReFinalize::visitEvent(Event* curr) { WASM_UNREACHABLE(); } void ReFinalize::visitModule(Module* curr) { WASM_UNREACHABLE(); } void ReFinalize::updateBreakValueType(Name name, Type type) { diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index 950b9bfcb..3f3d27f1b 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -29,6 +29,7 @@ struct ImportInfo { std::vector<Global*> importedGlobals; std::vector<Function*> importedFunctions; + std::vector<Event*> importedEvents; ImportInfo(Module& wasm) : wasm(wasm) { for (auto& import : wasm.globals) { @@ -41,6 +42,11 @@ struct ImportInfo { importedFunctions.push_back(import.get()); } } + for (auto& import : wasm.events) { + if (import->imported()) { + importedEvents.push_back(import.get()); + } + } } Global* getImportedGlobal(Name module, Name base) { @@ -61,13 +67,25 @@ struct ImportInfo { return nullptr; } + Event* getImportedEvent(Name module, Name base) { + for (auto* import : importedEvents) { + if (import->module == module && import->base == base) { + return import; + } + } + return nullptr; + } + Index getNumImportedGlobals() { return importedGlobals.size(); } Index getNumImportedFunctions() { return importedFunctions.size(); } + Index getNumImportedEvents() { return importedEvents.size(); } + Index getNumImports() { return getNumImportedGlobals() + getNumImportedFunctions() + - (wasm.memory.imported() ? 1 : 0) + (wasm.table.imported() ? 1 : 0); + getNumImportedEvents() + (wasm.memory.imported() ? 1 : 0) + + (wasm.table.imported() ? 1 : 0); } Index getNumDefinedGlobals() { @@ -77,6 +95,10 @@ struct ImportInfo { Index getNumDefinedFunctions() { return wasm.functions.size() - getNumImportedFunctions(); } + + Index getNumDefinedEvents() { + return wasm.events.size() - getNumImportedEvents(); + } }; } // namespace wasm diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index 5569843fd..067f59416 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -34,6 +34,7 @@ namespace ModuleUtils { struct BinaryIndexes { std::unordered_map<Name, Index> functionIndexes; std::unordered_map<Name, Index> globalIndexes; + std::unordered_map<Name, Index> eventIndexes; BinaryIndexes(Module& wasm) { auto addGlobal = [&](Global* curr) { @@ -66,6 +67,21 @@ struct BinaryIndexes { } } assert(functionIndexes.size() == wasm.functions.size()); + auto addEvent = [&](Event* curr) { + auto index = eventIndexes.size(); + eventIndexes[curr->name] = index; + }; + for (auto& curr : wasm.events) { + if (curr->imported()) { + addEvent(curr.get()); + } + } + for (auto& curr : wasm.events) { + if (!curr->imported()) { + addEvent(curr.get()); + } + } + assert(eventIndexes.size() == wasm.events.size()); } }; @@ -105,6 +121,16 @@ inline Global* copyGlobal(Global* global, Module& out) { return ret; } +inline Event* copyEvent(Event* event, Module& out) { + auto* ret = new Event(); + ret->name = event->name; + ret->attribute = event->attribute; + ret->type = event->type; + ret->params = event->params; + out.addEvent(ret); + return ret; +} + inline void copyModule(Module& in, Module& out) { // we use names throughout, not raw points, so simple copying is fine // for everything *but* expressions @@ -120,6 +146,9 @@ inline void copyModule(Module& in, Module& out) { for (auto& curr : in.globals) { copyGlobal(curr.get(), out); } + for (auto& curr : in.events) { + copyEvent(curr.get(), out); + } out.table = in.table; for (auto& segment : out.table.segments) { segment.offset = ExpressionManipulator::copy(segment.offset, out); @@ -243,6 +272,22 @@ template<typename T> inline void iterDefinedFunctions(Module& wasm, T visitor) { } } +template<typename T> inline void iterImportedEvents(Module& wasm, T visitor) { + for (auto& import : wasm.events) { + if (import->imported()) { + visitor(import.get()); + } + } +} + +template<typename T> inline void iterDefinedEvents(Module& wasm, T visitor) { + for (auto& import : wasm.events) { + if (!import->imported()) { + visitor(import.get()); + } + } +} + } // namespace ModuleUtils } // namespace wasm diff --git a/src/ir/utils.h b/src/ir/utils.h index a8af3ed18..b8e8fe815 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -154,6 +154,7 @@ struct ReFinalize void visitGlobal(Global* curr); void visitTable(Table* curr); void visitMemory(Memory* curr); + void visitEvent(Event* curr); void visitModule(Module* curr); private: @@ -208,6 +209,7 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> { void visitGlobal(Global* curr) { WASM_UNREACHABLE(); } void visitTable(Table* curr) { WASM_UNREACHABLE(); } void visitMemory(Memory* curr) { WASM_UNREACHABLE(); } + void visitEvent(Event* curr) { WASM_UNREACHABLE(); } void visitModule(Module* curr) { WASM_UNREACHABLE(); } // given a stack of nested expressions, update them all from child to parent diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 180d08bb5..d2703e425 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -84,6 +84,7 @@ Module['ExternalFunction'] = Module['_BinaryenExternalFunction'](); Module['ExternalTable'] = Module['_BinaryenExternalTable'](); Module['ExternalMemory'] = Module['_BinaryenExternalMemory'](); Module['ExternalGlobal'] = Module['_BinaryenExternalGlobal'](); +Module['ExternalEvent'] = Module['_BinaryenExternalEvent'](); // Features Module['Features'] = { @@ -1788,6 +1789,21 @@ function wrapModule(module, self) { return Module['_BinaryenRemoveGlobal'](module, strToStack(name)); }); } + self['addEvent'] = function(name, attribute, eventType) { + return preserveStack(function() { + return Module['_BinaryenAddEvent'](module, strToStack(name), attribute, eventType); + }); + }; + self['getEvent'] = function(name) { + return preserveStack(function() { + return Module['_BinaryenGetEvent'](module, strToStack(name)); + }); + }; + self['removeEvent'] = function(name) { + return preserveStack(function() { + return Module['_BinaryenRemoveEvent'](module, strToStack(name)); + }); + }; self['addFunctionImport'] = function(internalName, externalModuleName, externalBaseName, functionType) { return preserveStack(function() { return Module['_BinaryenAddFunctionImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), functionType); @@ -1808,6 +1824,11 @@ function wrapModule(module, self) { return Module['_BinaryenAddGlobalImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), globalType); }); }; + self['addEventImport'] = function(internalName, externalModuleName, externalBaseName, attribute, eventType) { + return preserveStack(function() { + return Module['_BinaryenAddEventImport'](module, strToStack(internalName), strToStack(externalModuleName), strToStack(externalBaseName), attribute, eventType); + }); + }; self['addExport'] = // deprecated self['addFunctionExport'] = function(internalName, externalName) { return preserveStack(function() { @@ -1829,6 +1850,11 @@ function wrapModule(module, self) { return Module['_BinaryenAddGlobalExport'](module, strToStack(internalName), strToStack(externalName)); }); }; + self['addEventExport'] = function(internalName, externalName) { + return preserveStack(function() { + return Module['_BinaryenAddEventExport'](module, strToStack(internalName), strToStack(externalName)); + }); + }; self['removeExport'] = function(externalName) { return preserveStack(function() { return Module['_BinaryenRemoveExport'](module, strToStack(externalName)); @@ -2354,6 +2380,17 @@ Module['getGlobalInfo'] = function(global) { }; }; +// Obtains information about a 'Event' +Module['getEventInfo'] = function(event_) { + return { + 'name': UTF8ToString(Module['_BinaryenEventGetName'](event_)), + 'module': UTF8ToString(Module['_BinaryenEventImportGetModule'](event_)), + 'base': UTF8ToString(Module['_BinaryenEventImportGetBase'](event_)), + 'attribute': Module['_BinaryenEventGetAttribute'](event_), + 'type': UTF8ToString(Module['_BinaryenEventGetType'](event_)) + }; +}; + // Obtains information about an 'Export' Module['getExportInfo'] = function(export_) { return { diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp index af5a62697..a408ccf95 100644 --- a/src/passes/Metrics.cpp +++ b/src/passes/Metrics.cpp @@ -66,6 +66,7 @@ struct Metrics counts["[imports]"] = imports.getNumImports(); counts["[funcs]"] = imports.getNumDefinedFunctions(); counts["[globals]"] = imports.getNumDefinedGlobals(); + counts["[events]"] = imports.getNumDefinedEvents(); counts["[exports]"] = module->exports.size(); // add memory and table if (module->memory.exists) { diff --git a/src/passes/MinifyImportsAndExports.cpp b/src/passes/MinifyImportsAndExports.cpp index 23dd2a21a..043cfb588 100644 --- a/src/passes/MinifyImportsAndExports.cpp +++ b/src/passes/MinifyImportsAndExports.cpp @@ -159,6 +159,7 @@ private: }; ModuleUtils::iterImportedGlobals(*module, processImport); ModuleUtils::iterImportedFunctions(*module, processImport); + ModuleUtils::iterImportedEvents(*module, processImport); if (minifyExports) { // Minify the exported names. diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index fb85023f0..9dbf3cc1f 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1660,6 +1660,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> { case ExternalKind::Global: o << "global"; break; + case ExternalKind::Event: + o << "event"; + break; case ExternalKind::Invalid: WASM_UNREACHABLE(); } @@ -1805,6 +1808,25 @@ struct PrintSExpression : public Visitor<PrintSExpression> { } o << maybeNewLine; } + void visitEvent(Event* curr) { + doIndent(o, indent); + if (curr->imported()) { + o << '('; + emitImportHeader(curr); + } + o << "(event "; + printName(curr->name, o); + o << maybeSpace << "(attr " << curr->attribute << ')' << maybeSpace << '('; + printMinor(o, "param"); + for (auto& param : curr->params) { + o << ' ' << printType(param); + } + o << "))"; + if (curr->imported()) { + o << ')'; + } + o << maybeNewLine; + } void printTableHeader(Table* curr) { o << '('; printMedium(o, "table") << ' '; @@ -1948,12 +1970,16 @@ struct PrintSExpression : public Visitor<PrintSExpression> { *curr, [&](Global* global) { visitGlobal(global); }); ModuleUtils::iterImportedFunctions( *curr, [&](Function* func) { visitFunction(func); }); + ModuleUtils::iterImportedEvents(*curr, + [&](Event* event) { visitEvent(event); }); ModuleUtils::iterDefinedMemories( *curr, [&](Memory* memory) { visitMemory(memory); }); ModuleUtils::iterDefinedTables(*curr, [&](Table* table) { visitTable(table); }); ModuleUtils::iterDefinedGlobals( *curr, [&](Global* global) { visitGlobal(global); }); + ModuleUtils::iterDefinedEvents(*curr, + [&](Event* event) { visitEvent(event); }); for (auto& child : curr->exports) { doIndent(o, indent); visitExport(child.get()); diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index c96ce1a8c..20c30d271 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -15,9 +15,9 @@ */ // -// Removes module elements that are are never used: functions and globals, -// which may be imported or not, and function types (which we merge -// and remove if unneeded) +// Removes module elements that are are never used: functions, globals, and +// events, which may be imported or not, and function types (which we merge and +// remove if unneeded) // #include <memory> @@ -30,7 +30,7 @@ namespace wasm { -enum class ModuleElementKind { Function, Global }; +enum class ModuleElementKind { Function, Global, Event }; typedef std::pair<ModuleElementKind, Name> ModuleElement; @@ -68,7 +68,7 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { if (!func->imported()) { walk(func->body); } - } else { + } else if (curr.first == ModuleElementKind::Global) { // if not imported, it has an init expression we need to walk auto* global = module->getGlobal(curr.second); if (!global->imported()) { @@ -122,6 +122,7 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { struct FunctionTypeAnalyzer : public PostWalker<FunctionTypeAnalyzer> { std::vector<Function*> functions; std::vector<CallIndirect*> indirectCalls; + std::vector<Event*> events; void visitFunction(Function* curr) { if (curr->type.is()) { @@ -129,6 +130,8 @@ struct FunctionTypeAnalyzer : public PostWalker<FunctionTypeAnalyzer> { } } + void visitEvent(Event* curr) { events.push_back(curr); } + void visitCallIndirect(CallIndirect* curr) { indirectCalls.push_back(curr); } }; @@ -139,11 +142,11 @@ struct RemoveUnusedModuleElements : public Pass { : rootAllFunctions(rootAllFunctions) {} void run(PassRunner* runner, Module* module) override { - optimizeGlobalsAndFunctions(module); + optimizeGlobalsAndFunctionsAndEvents(module); optimizeFunctionTypes(module); } - void optimizeGlobalsAndFunctions(Module* module) { + void optimizeGlobalsAndFunctionsAndEvents(Module* module) { std::vector<ModuleElement> roots; // Module start is a root. if (module->start.is()) { @@ -169,6 +172,8 @@ struct RemoveUnusedModuleElements : public Pass { roots.emplace_back(ModuleElementKind::Function, curr->value); } else if (curr->kind == ExternalKind::Global) { roots.emplace_back(ModuleElementKind::Global, curr->value); + } else if (curr->kind == ExternalKind::Event) { + roots.emplace_back(ModuleElementKind::Event, curr->value); } else if (curr->kind == ExternalKind::Memory) { exportsMemory = true; } else if (curr->kind == ExternalKind::Table) { @@ -215,6 +220,17 @@ struct RemoveUnusedModuleElements : public Pass { }), v.end()); } + { + auto& v = module->events; + v.erase(std::remove_if(v.begin(), + v.end(), + [&](const std::unique_ptr<Event>& curr) { + return analyzer.reachable.count( + ModuleElement(ModuleElementKind::Event, + curr->name)) == 0; + }), + v.end()); + } module->updateMaps(); // Handle the memory and table if (!exportsMemory && !analyzer.usesMemory) { @@ -272,6 +288,9 @@ struct RemoveUnusedModuleElements : public Pass { for (auto* call : analyzer.indirectCalls) { call->fullType = canonicalize(call->fullType); } + for (auto* event : analyzer.events) { + event->type = canonicalize(event->type); + } // remove no-longer used types module->functionTypes.erase( std::remove_if(module->functionTypes.begin(), diff --git a/src/shared-constants.h b/src/shared-constants.h index 9e119dc95..9fb84dbf8 100644 --- a/src/shared-constants.h +++ b/src/shared-constants.h @@ -62,6 +62,8 @@ extern Name SPECTEST; extern Name PRINT; extern Name EXIT; extern Name SHARED; +extern Name EVENT; +extern Name ATTR; } // namespace wasm diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index f7dd20e76..0a7128e3e 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -197,6 +197,9 @@ public: } setupTable(); setupGlobals(); + if (wasm.features.hasExceptionHandling()) { + setupEvents(); + } addImportLoggingSupport(); // keep adding functions until we run out of input while (!finishedInput) { @@ -397,6 +400,28 @@ private: } } + void setupEvents() { + Index num = upTo(3); + for (size_t i = 0; i < num; i++) { + // Events should have void return type and at least one param type + Type type = pick(i32, i64, f32, f64); + std::string sig = std::string("v") + getSig(type); + std::vector<Type> params; + params.push_back(type); + Index numValues = upToSquared(MAX_PARAMS - 1); + for (Index i = 0; i < numValues; i++) { + type = pick(i32, i64, f32, f64); + sig += getSig(type); + params.push_back(type); + } + auto* event = builder.makeEvent(std::string("event$") + std::to_string(i), + WASM_EVENT_ATTRIBUTE_EXCEPTION, + ensureFunctionType(sig, &wasm)->name, + std::move(params)); + wasm.addEvent(event); + } + } + void finalizeTable() { wasm.table.initial = wasm.table.segments[0].data.size(); wasm.table.max = diff --git a/src/tools/wasm-metadce.cpp b/src/tools/wasm-metadce.cpp index c04286f59..96b368bc4 100644 --- a/src/tools/wasm-metadce.cpp +++ b/src/tools/wasm-metadce.cpp @@ -55,10 +55,12 @@ struct MetaDCEGraph { std::unordered_map<Name, Name> exportToDCENode; std::unordered_map<Name, Name> functionToDCENode; // function name => DCE name std::unordered_map<Name, Name> globalToDCENode; // global name => DCE name + std::unordered_map<Name, Name> eventToDCENode; // event name => DCE name std::unordered_map<Name, Name> DCENodeToExport; // reverse maps std::unordered_map<Name, Name> DCENodeToFunction; std::unordered_map<Name, Name> DCENodeToGlobal; + std::unordered_map<Name, Name> DCENodeToEvent; // imports are not mapped 1:1 to DCE nodes in the wasm, since env.X might // be imported twice, for example. So we don't map a DCE node to an Import, @@ -80,6 +82,11 @@ struct MetaDCEGraph { return getImportId(imp->module, imp->base); } + ImportId getEventImportId(Name name) { + auto* imp = wasm.getEvent(name); + return getImportId(imp->module, imp->base); + } + // import module.base => DCE name std::unordered_map<Name, Name> importIdToDCENode; @@ -106,8 +113,14 @@ struct MetaDCEGraph { globalToDCENode[global->name] = dceName; nodes[dceName] = DCENode(dceName); }); - // only process function and global imports - the table and memory are - // always there + ModuleUtils::iterDefinedEvents(wasm, [&](Event* event) { + auto dceName = getName("event", event->name.str); + DCENodeToEvent[dceName] = event->name; + eventToDCENode[event->name] = dceName; + nodes[dceName] = DCENode(dceName); + }); + // only process function, global, and event imports - the table and memory + // are always there ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) { auto id = getImportId(import->module, import->base); if (importIdToDCENode.find(id) == importIdToDCENode.end()) { @@ -122,6 +135,13 @@ struct MetaDCEGraph { importIdToDCENode[id] = dceName; } }); + ModuleUtils::iterImportedEvents(wasm, [&](Event* import) { + auto id = getImportId(import->module, import->base); + if (importIdToDCENode.find(id) == importIdToDCENode.end()) { + auto dceName = getName("importId", import->name.str); + importIdToDCENode[id] = dceName; + } + }); for (auto& exp : wasm.exports) { if (exportToDCENode.find(exp->name) == exportToDCENode.end()) { auto dceName = getName("export", exp->name.str); @@ -145,6 +165,13 @@ struct MetaDCEGraph { node.reaches.push_back( importIdToDCENode[getGlobalImportId(exp->value)]); } + } else if (exp->kind == ExternalKind::Event) { + if (!wasm.getEvent(exp->value)->imported()) { + node.reaches.push_back(eventToDCENode[exp->value]); + } else { + node.reaches.push_back( + importIdToDCENode[getEventImportId(exp->value)]); + } } } // Add initializer dependencies @@ -355,6 +382,9 @@ public: if (DCENodeToGlobal.find(name) != DCENodeToGlobal.end()) { std::cout << " is global " << DCENodeToGlobal[name] << '\n'; } + if (DCENodeToEvent.find(name) != DCENodeToEvent.end()) { + std::cout << " is event " << DCENodeToEvent[name] << '\n'; + } for (auto target : node.reaches) { std::cout << " reaches: " << target.str << '\n'; } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index ce3144715..e2323967e 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -363,6 +363,7 @@ enum Section { Code = 10, Data = 11, DataCount = 12, + Event = 13 }; enum SegmentFlag { @@ -948,13 +949,18 @@ public: void writeExports(); void writeDataCount(); void writeDataSegments(); + void writeEvents(); // name of the Function => index. first imports, then internals std::unordered_map<Name, Index> mappedFunctions; // name of the Global => index. first imported globals, then internal globals std::unordered_map<Name, uint32_t> mappedGlobals; + // name of the Event => index. first imported events, then internal events + std::unordered_map<Name, uint32_t> mappedEvents; + uint32_t getFunctionIndex(Name name); uint32_t getGlobalIndex(Name name); + uint32_t getEventIndex(Name name); void writeFunctionTableDeclaration(); void writeTableElements(); @@ -1071,6 +1077,7 @@ public: // gets a name in the combined import+defined space Name getFunctionName(Index index); Name getGlobalName(Index index); + Name getEventName(Index index); void getResizableLimits(Address& initial, Address& max, @@ -1165,6 +1172,9 @@ public: void readFunctionTableDeclaration(); void readTableElements(); + + void readEvents(); + void readNames(size_t); void readFeatures(size_t); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 0b7326b6e..284608105 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -683,6 +683,19 @@ public: glob->mutable_ = mutable_ == Mutable; return glob; } + + // TODO Remove 'type' parameter once we remove FunctionType + static Event* makeEvent(Name name, + uint32_t attribute, + Name type, + std::vector<Type>&& params) { + auto* event = new Event; + event->name = name; + event->attribute = attribute; + event->type = type; + event->params = params; + return event; + } }; } // namespace wasm diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index d501a349a..71249748e 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -113,8 +113,10 @@ class SExpressionWasmBuilder { MixedArena& allocator; std::vector<Name> functionNames; std::vector<Name> globalNames; - int functionCounter; + std::vector<Name> eventNames; + int functionCounter = 0; int globalCounter = 0; + int eventCounter = 0; // we need to know function return types before we parse their contents std::map<Name, Type> functionTypes; std::unordered_map<cashew::IString, Index> debugInfoFileIndices; @@ -142,6 +144,7 @@ private: Name getFunctionName(Element& s); Name getFunctionTypeName(Element& s); Name getGlobalName(Element& s); + Name getEventName(Element& s); void parseStart(Element& s) { wasm.addStart(getFunctionName(*s[1])); } // returns the next index in s @@ -247,6 +250,7 @@ private: void parseElem(Element& s); void parseInnerElem(Element& s, Index i = 1, Expression* offset = nullptr); void parseType(Element& s); + void parseEvent(Element& s, bool preParseImport = false); Function::DebugLocation getDebugLocation(const SourceLocation& loc); }; diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h index 73f57a538..f1306721e 100644 --- a/src/wasm-traversal.h +++ b/src/wasm-traversal.h @@ -79,6 +79,7 @@ template<typename SubType, typename ReturnType = void> struct Visitor { ReturnType visitFunction(Function* curr) { return ReturnType(); } ReturnType visitTable(Table* curr) { return ReturnType(); } ReturnType visitMemory(Memory* curr) { return ReturnType(); } + ReturnType visitEvent(Event* curr) { return ReturnType(); } ReturnType visitModule(Module* curr) { return ReturnType(); } ReturnType visit(Expression* curr) { @@ -223,6 +224,7 @@ struct OverriddenVisitor { UNIMPLEMENTED(Function); UNIMPLEMENTED(Table); UNIMPLEMENTED(Memory); + UNIMPLEMENTED(Event); UNIMPLEMENTED(Module); #undef UNIMPLEMENTED @@ -486,6 +488,10 @@ struct Walker : public VisitorType { setFunction(nullptr); } + void walkEvent(Event* event) { + static_cast<SubType*>(this)->visitEvent(event); + } + void walkFunctionInModule(Function* func, Module* module) { setModule(module); setFunction(func); @@ -545,6 +551,13 @@ struct Walker : public VisitorType { self->walkFunction(curr.get()); } } + for (auto& curr : module->events) { + if (curr->imported()) { + self->visitEvent(curr.get()); + } else { + self->walkEvent(curr.get()); + } + } self->walkTable(&module->table); self->walkMemory(&module->memory); } diff --git a/src/wasm.h b/src/wasm.h index d4ffe86f2..de3289289 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1063,6 +1063,7 @@ enum class ExternalKind { Table = 1, Memory = 2, Global = 3, + Event = 4, Invalid = -1 }; @@ -1156,6 +1157,24 @@ public: bool mutable_ = false; }; +// Kinds of event attributes. +enum WasmEventAttribute : unsigned { WASM_EVENT_ATTRIBUTE_EXCEPTION = 0x0 }; + +class Event : public Importable { +public: + Name name; + // Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible. + uint32_t attribute; + // Type string in the format of function type. Return type is considered as a + // void type. So if you have an event whose type is (i32, i32), the type + // string will be "vii". + Name type; + // This is duplicate info of 'Name type', but we store this anyway because + // we plan to remove FunctionType in future. + // TODO remove either this or FunctionType + std::vector<Type> params; +}; + // "Opaque" data, not part of the core wasm spec, that is held in binaries. // May be parsed/handled by utility code elsewhere, but not in wasm.h class UserSection { @@ -1172,6 +1191,7 @@ public: std::vector<std::unique_ptr<Export>> exports; std::vector<std::unique_ptr<Function>> functions; std::vector<std::unique_ptr<Global>> globals; + std::vector<std::unique_ptr<Event>> events; Table table; Memory memory; @@ -1197,6 +1217,7 @@ private: std::map<Name, Export*> exportsMap; std::map<Name, Function*> functionsMap; std::map<Name, Global*> globalsMap; + std::map<Name, Event*> eventsMap; public: Module() = default; @@ -1205,17 +1226,20 @@ public: Export* getExport(Name name); Function* getFunction(Name name); Global* getGlobal(Name name); + Event* getEvent(Name name); FunctionType* getFunctionTypeOrNull(Name name); Export* getExportOrNull(Name name); Function* getFunctionOrNull(Name name); Global* getGlobalOrNull(Name name); + Event* getEventOrNull(Name name); FunctionType* addFunctionType(std::unique_ptr<FunctionType> curr); Export* addExport(Export* curr); Function* addFunction(Function* curr); Function* addFunction(std::unique_ptr<Function> curr); Global* addGlobal(Global* curr); + Event* addEvent(Event* curr); void addStart(const Name& s); @@ -1223,6 +1247,7 @@ public: void removeExport(Name name); void removeFunction(Name name); void removeGlobal(Name name); + void removeEvent(Name name); void updateMaps(); diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d8ce18de5..91a2184e9 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -37,6 +37,7 @@ void WasmBinaryWriter::prepare() { ModuleUtils::BinaryIndexes indexes(*wasm); mappedFunctions = std::move(indexes.functionIndexes); mappedGlobals = std::move(indexes.globalIndexes); + mappedEvents = std::move(indexes.eventIndexes); importInfo = wasm::make_unique<ImportInfo>(*wasm); } @@ -63,6 +64,7 @@ void WasmBinaryWriter::write() { writeDataCount(); writeFunctions(); writeDataSegments(); + writeEvents(); if (debugInfo) { writeNames(); } @@ -245,6 +247,15 @@ void WasmBinaryWriter::writeImports() { o << binaryType(global->type); o << U32LEB(global->mutable_); }); + ModuleUtils::iterImportedEvents(*wasm, [&](Event* event) { + if (debug) { + std::cerr << "write one event" << std::endl; + } + writeImportHeader(event); + o << U32LEB(int32_t(ExternalKind::Event)); + o << U32LEB(event->attribute); + o << U32LEB(getFunctionTypeIndex(event->type)); + }); if (wasm->memory.imported()) { if (debug) { std::cerr << "write one memory" << std::endl; @@ -401,6 +412,9 @@ void WasmBinaryWriter::writeExports() { case ExternalKind::Global: o << U32LEB(getGlobalIndex(curr->value)); break; + case ExternalKind::Event: + o << U32LEB(getEventIndex(curr->value)); + break; default: WASM_UNREACHABLE(); } @@ -453,6 +467,11 @@ uint32_t WasmBinaryWriter::getGlobalIndex(Name name) { return mappedGlobals[name]; } +uint32_t WasmBinaryWriter::getEventIndex(Name name) { + assert(mappedEvents.count(name)); + return mappedEvents[name]; +} + void WasmBinaryWriter::writeFunctionTableDeclaration() { if (!wasm->table.exists || wasm->table.imported()) { return; @@ -493,6 +512,27 @@ void WasmBinaryWriter::writeTableElements() { finishSection(start); } +void WasmBinaryWriter::writeEvents() { + if (importInfo->getNumDefinedEvents() == 0) { + return; + } + if (debug) { + std::cerr << "== writeEvents" << std::endl; + } + auto start = startSection(BinaryConsts::Section::Event); + auto num = importInfo->getNumDefinedEvents(); + o << U32LEB(num); + ModuleUtils::iterDefinedEvents(*wasm, [&](Event* event) { + if (debug) { + std::cerr << "write one" << std::endl; + } + o << U32LEB(event->attribute); + o << U32LEB(getFunctionTypeIndex(event->type)); + }); + + finishSection(start); +} + void WasmBinaryWriter::writeNames() { bool hasContents = false; if (wasm->functions.size() > 0) { @@ -828,6 +868,9 @@ void WasmBinaryBuilder::read() { case BinaryConsts::Section::Table: readFunctionTableDeclaration(); break; + case BinaryConsts::Section::Event: + readEvents(); + break; default: { readUserSection(payloadLen); if (pos > oldPos + payloadLen) { @@ -1210,6 +1253,13 @@ Name WasmBinaryBuilder::getGlobalName(Index index) { return wasm.globals[index]->name; } +Name WasmBinaryBuilder::getEventName(Index index) { + if (index >= wasm.events.size()) { + throwError("invalid event index"); + } + return wasm.events[index]->name; +} + void WasmBinaryBuilder::getResizableLimits(Address& initial, Address& max, bool& shared, @@ -1310,6 +1360,23 @@ void WasmBinaryBuilder::readImports() { wasm.addGlobal(curr); break; } + case ExternalKind::Event: { + auto name = Name(std::string("eimport$") + std::to_string(i)); + auto attribute = getU32LEB(); + auto index = getU32LEB(); + if (index >= wasm.functionTypes.size()) { + throwError("invalid event index " + std::to_string(index) + " / " + + std::to_string(wasm.functionTypes.size())); + } + Name type = wasm.functionTypes[index]->name; + std::vector<Type> params = wasm.functionTypes[index]->params; + auto* curr = + builder.makeEvent(name, attribute, type, std::move(params)); + curr->module = module; + curr->base = base; + wasm.addEvent(curr); + break; + } default: { throwError("bad import kind"); } } } @@ -1841,6 +1908,9 @@ void WasmBinaryBuilder::processFunctions() { case ExternalKind::Global: curr->value = getGlobalName(index); break; + case ExternalKind::Event: + curr->value = getEventName(index); + break; default: throwError("bad export kind"); } @@ -1954,6 +2024,31 @@ void WasmBinaryBuilder::readTableElements() { } } +void WasmBinaryBuilder::readEvents() { + if (debug) { + std::cerr << "== readEvents" << std::endl; + } + size_t numEvents = getU32LEB(); + if (debug) { + std::cerr << "num: " << numEvents << std::endl; + } + for (size_t i = 0; i < numEvents; i++) { + if (debug) { + std::cerr << "read one" << std::endl; + } + auto attribute = getU32LEB(); + auto typeIndex = getU32LEB(); + if (typeIndex >= wasm.functionTypes.size()) { + throwError("invalid event index " + std::to_string(typeIndex) + " / " + + std::to_string(wasm.functionTypes.size())); + } + Name type = wasm.functionTypes[typeIndex]->name; + std::vector<Type> params = wasm.functionTypes[typeIndex]->params; + wasm.addEvent(Builder::makeEvent( + "event$" + std::to_string(i), attribute, type, std::move(params))); + } +} + static bool isIdChar(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '!' || ch == '#' || ch == '$' || diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 3a5dfbced..8ead42608 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -388,6 +388,8 @@ void SExpressionWasmBuilder::preParseImports(Element& curr) { parseTable(curr, true /* preParseImport */); } else if (id == MEMORY) { parseMemory(curr, true /* preParseImport */); + } else if (id == EVENT) { + parseEvent(curr, true /* preParseImport */); } else { throw ParseException( "fancy import we don't support yet", curr.line, curr.col); @@ -430,6 +432,9 @@ void SExpressionWasmBuilder::parseModuleElement(Element& curr) { if (id == TYPE) { return; // already done } + if (id == EVENT) { + return parseEvent(curr); + } std::cerr << "bad module element " << id.str << '\n'; throw ParseException("unknown module element", curr.line, curr.col); } @@ -473,6 +478,19 @@ Name SExpressionWasmBuilder::getGlobalName(Element& s) { } } +Name SExpressionWasmBuilder::getEventName(Element& s) { + if (s.dollared()) { + return s.str(); + } else { + // index + size_t offset = atoi(s.str().c_str()); + if (offset >= eventNames.size()) { + throw ParseException("unknown event in getEventName"); + } + return eventNames[offset]; + } +} + // Parse various forms of (param ...) or (local ...) element. This ignores all // parameter or local names when specified. std::vector<Type> SExpressionWasmBuilder::parseParamOrLocal(Element& s) { @@ -1877,6 +1895,8 @@ void SExpressionWasmBuilder::parseExport(Element& s) { ex->kind = ExternalKind::Table; } else if (elementStartsWith(inner, GLOBAL)) { ex->kind = ExternalKind::Global; + } else if (inner[0]->str() == EVENT) { + ex->kind = ExternalKind::Event; } else { throw ParseException("invalid export"); } @@ -1913,6 +1933,8 @@ void SExpressionWasmBuilder::parseImport(Element& s) { wasm.table.exists = true; } else if (elementStartsWith(*s[3], GLOBAL)) { kind = ExternalKind::Global; + } else if ((*s[3])[0]->str() == EVENT) { + kind = ExternalKind::Event; } else { newStyle = false; // either (param..) or (result..) } @@ -1936,6 +1958,9 @@ void SExpressionWasmBuilder::parseImport(Element& s) { name = Name("import$memory$" + std::to_string(0)); } else if (kind == ExternalKind::Table) { name = Name("import$table$" + std::to_string(0)); + } else if (kind == ExternalKind::Event) { + name = Name("import$event" + std::to_string(eventCounter++)); + eventNames.push_back(name); } else { throw ParseException("invalid import"); } @@ -1957,7 +1982,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { if (kind == ExternalKind::Function) { FunctionType* functionType = nullptr; auto func = make_unique<Function>(); - parseTypeUse(inner, j, functionType, func->params, func->result); + j = parseTypeUse(inner, j, functionType, func->params, func->result); func->name = name; func->module = module; func->base = base; @@ -1968,9 +1993,9 @@ void SExpressionWasmBuilder::parseImport(Element& s) { Type type; bool mutable_ = false; if (inner[j]->isStr()) { - type = stringToType(inner[j]->str()); + type = stringToType(inner[j++]->str()); } else { - auto& inner2 = *inner[j]; + auto& inner2 = *inner[j++]; if (inner2[0]->str() != MUT) { throw ParseException("expected mut"); } @@ -1997,6 +2022,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { } else { wasm.table.max = Table::kUnlimitedSize; } + j++; // funcref // ends with the table element type } else if (kind == ExternalKind::Memory) { wasm.memory.module = module; @@ -2007,10 +2033,32 @@ void SExpressionWasmBuilder::parseImport(Element& s) { throw ParseException("bad memory limit declaration"); } wasm.memory.shared = true; - parseMemoryLimits(limits, 1); + j = parseMemoryLimits(limits, 1); } else { - parseMemoryLimits(inner, j); + j = parseMemoryLimits(inner, j); + } + } else if (kind == ExternalKind::Event) { + FunctionType* functionType = nullptr; + auto event = make_unique<Event>(); + if (j >= inner.size()) { + throw ParseException("event does not have an attribute", s.line, s.col); + } + auto& attrElem = *inner[j++]; + if (!elementStartsWith(attrElem, ATTR) || attrElem.size() != 2) { + throw ParseException("invalid attribute", attrElem.line, attrElem.col); } + event->attribute = atoi(attrElem[1]->c_str()); + Type fakeResult; // just to call parseTypeUse + j = parseTypeUse(inner, j, functionType, event->params, fakeResult); + event->name = name; + event->module = module; + event->base = base; + event->type = functionType->name; + wasm.addEvent(event.release()); + } + // If there are more elements, they are invalid + if (j < inner.size()) { + throw ParseException("invalid element", inner[j]->line, inner[j]->col); } } @@ -2234,4 +2282,95 @@ void SExpressionWasmBuilder::parseType(Element& s) { wasm.addFunctionType(std::move(type)); } +void SExpressionWasmBuilder::parseEvent(Element& s, bool preParseImport) { + auto event = make_unique<Event>(); + size_t i = 1; + + // Parse name + if (s[i]->isStr() && s[i]->dollared()) { + auto& inner = *s[i++]; + event->name = inner.str(); + if (wasm.getEventOrNull(event->name)) { + throw ParseException("duplicate event", inner.line, inner.col); + } + } else { + event->name = Name::fromInt(eventCounter); + assert(!wasm.getEventOrNull(event->name)); + } + eventCounter++; + eventNames.push_back(event->name); + + // Parse import, if any + if (i < s.size() && elementStartsWith(*s[i], IMPORT)) { + assert(preParseImport && "import element in non-preParseImport mode"); + auto& importElem = *s[i++]; + if (importElem.size() != 3) { + throw ParseException("invalid import", importElem.line, importElem.col); + } + if (!importElem[1]->isStr() || importElem[1]->dollared()) { + throw ParseException( + "invalid import module name", importElem[1]->line, importElem[1]->col); + } + if (!importElem[2]->isStr() || importElem[2]->dollared()) { + throw ParseException( + "invalid import base name", importElem[2]->line, importElem[2]->col); + } + event->module = importElem[1]->str(); + event->base = importElem[2]->str(); + } + + // Parse export, if any + if (i < s.size() && elementStartsWith(*s[i], EXPORT)) { + auto& exportElem = *s[i++]; + if (event->module.is()) { + throw ParseException("import and export cannot be specified together", + exportElem.line, + exportElem.col); + } + if (exportElem.size() != 2) { + throw ParseException("invalid export", exportElem.line, exportElem.col); + } + if (!exportElem[1]->isStr() || exportElem[1]->dollared()) { + throw ParseException( + "invalid export name", exportElem[1]->line, exportElem[1]->col); + } + auto ex = make_unique<Export>(); + ex->name = exportElem[1]->str(); + if (wasm.getExportOrNull(ex->name)) { + throw ParseException( + "duplicate export", exportElem[1]->line, exportElem[1]->col); + } + ex->value = event->name; + ex->kind = ExternalKind::Event; + } + + // Parse attribute + if (i >= s.size()) { + throw ParseException("event does not have an attribute", s.line, s.col); + } + auto& attrElem = *s[i++]; + if (!elementStartsWith(attrElem, ATTR) || attrElem.size() != 2) { + throw ParseException("invalid attribute", attrElem.line, attrElem.col); + } + if (!attrElem[1]->isStr()) { + throw ParseException( + "invalid attribute", attrElem[1]->line, attrElem[1]->col); + } + event->attribute = atoi(attrElem[1]->c_str()); + + // Parse typeuse + FunctionType* functionType = nullptr; + Type fakeResult; // just co call parseTypeUse + i = parseTypeUse(s, i, functionType, event->params, fakeResult); + assert(functionType && "functionType should've been set by parseTypeUse"); + event->type = functionType->name; + + // If there are more elements, they are invalid + if (i < s.size()) { + throw ParseException("invalid element", s[i]->line, s[i]->col); + } + + wasm.addEvent(event.release()); +} + } // namespace wasm diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index ebaba3f24..2c2723bf6 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -68,6 +68,9 @@ FeatureSet getFeatures(Type type) { if (type == v128) { return FeatureSet::SIMD; } + if (type == except_ref) { + return FeatureSet::ExceptionHandling; + } return FeatureSet(); } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 01fe7e976..1d12c2452 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1745,6 +1745,10 @@ static void validateExports(Module& module, ValidationInfo& info) { info.shouldBeTrue(name == Name("0") || name == module.memory.name, name, "module memory exports must be found"); + } else if (exp->kind == ExternalKind::Event) { + info.shouldBeTrue(module.getEventOrNull(name), + name, + "module event exports must be found"); } else { WASM_UNREACHABLE(); } @@ -1855,6 +1859,36 @@ static void validateTable(Module& module, ValidationInfo& info) { } } +static void validateEvents(Module& module, ValidationInfo& info) { + if (!module.events.empty()) { + info.shouldBeTrue(module.features.hasExceptionHandling(), + module.events[0]->name, + "Module has events (event-handling is disabled)"); + } + for (auto& curr : module.events) { + info.shouldBeTrue( + curr->type.is(), curr->name, "Event should have a valid type"); + FunctionType* ft = module.getFunctionType(curr->type); + info.shouldBeEqual( + ft->result, none, curr->name, "Event type's result type should be none"); + info.shouldBeTrue(!curr->params.empty(), + curr->name, + "There should be 1 or more values in an event type"); + info.shouldBeEqual(curr->attribute, + (unsigned)0, + curr->attribute, + "Currently only attribute 0 is supported"); + for (auto type : curr->params) { + info.shouldBeTrue(isIntegerType(type) || isFloatType(type), + curr->name, + "Values in an event should have integer or float type"); + } + info.shouldBeTrue(curr->params == ft->params, + curr->name, + "Event's function type and internal type should match"); + } +} + static void validateModule(Module& module, ValidationInfo& info) { // start if (module.start.is()) { @@ -1889,6 +1923,7 @@ bool WasmValidator::validate(Module& module, Flags flags) { validateGlobals(module, info); validateMemory(module, info); validateTable(module, info); + validateEvents(module, info); validateModule(module, info); } // validate additional internal IR details when in pass-debug mode diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index c32ead836..c543686ed 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -82,6 +82,8 @@ Name SPECTEST("spectest"); Name PRINT("print"); Name EXIT("exit"); Name SHARED("shared"); +Name EVENT("event"); +Name ATTR("attr"); // Expressions @@ -908,11 +910,20 @@ Function* Module::getFunction(Name name) { Global* Module::getGlobal(Name name) { auto iter = globalsMap.find(name); if (iter == globalsMap.end()) { + assert(false); Fatal() << "Module::getGlobal: " << name << " does not exist"; } return iter->second; } +Event* Module::getEvent(Name name) { + auto iter = eventsMap.find(name); + if (iter == eventsMap.end()) { + Fatal() << "Module::getEvent: " << name << " does not exist"; + } + return iter->second; +} + FunctionType* Module::getFunctionTypeOrNull(Name name) { auto iter = functionTypesMap.find(name); if (iter == functionTypesMap.end()) { @@ -945,6 +956,14 @@ Global* Module::getGlobalOrNull(Name name) { return iter->second; } +Event* Module::getEventOrNull(Name name) { + auto iter = eventsMap.find(name); + if (iter == eventsMap.end()) { + return nullptr; + } + return iter->second; +} + FunctionType* Module::addFunctionType(std::unique_ptr<FunctionType> curr) { if (!curr->name.is()) { Fatal() << "Module::addFunctionType: empty name"; @@ -1009,6 +1028,20 @@ Global* Module::addGlobal(Global* curr) { return curr; } +Event* Module::addEvent(Event* curr) { + if (!curr->name.is()) { + Fatal() << "Module::addEvent: empty name"; + } + if (getEventOrNull(curr->name)) { + Fatal() << "Module::addEvent: " << curr->name << " already exists"; + } + + events.emplace_back(curr); + + eventsMap[curr->name] = curr; + return curr; +} + void Module::addStart(const Name& s) { start = s; } void Module::removeFunctionType(Name name) { @@ -1051,6 +1084,16 @@ void Module::removeGlobal(Name name) { globalsMap.erase(name); } +void Module::removeEvent(Name name) { + for (size_t i = 0; i < events.size(); i++) { + if (events[i]->name == name) { + events.erase(events.begin() + i); + break; + } + } + eventsMap.erase(name); +} + // TODO: remove* for other elements void Module::updateMaps() { @@ -1070,6 +1113,10 @@ void Module::updateMaps() { for (auto& curr : globals) { globalsMap[curr->name] = curr.get(); } + eventsMap.clear(); + for (auto& curr : events) { + eventsMap[curr->name] = curr.get(); + } } void Module::clearDebugInfo() { debugInfoFileNames.clear(); } diff --git a/test/binaryen.js/event.js b/test/binaryen.js/event.js new file mode 100644 index 000000000..ec7a0f3b1 --- /dev/null +++ b/test/binaryen.js/event.js @@ -0,0 +1,32 @@ +function cleanInfo(info) { + var ret = {}; + for (var x in info) { + ret[x] = info[x]; + } + return ret; +} + +var module = new Binaryen.Module(); +module.setFeatures(Binaryen.Features.ExceptionHandling); + +var vi = module.addFunctionType("vi", Binaryen.none, [Binaryen.i32]); +var vif = module.addFunctionType("vif", Binaryen.none, [Binaryen.i32, Binaryen.f32]); + +var event_ = module.addEvent("a-event", 0, vi); + +console.log("GetEvent is equal: " + (event_ === module.getEvent("a-event"))); + +var eventInfo = Binaryen.getEventInfo(event_); +console.log("getEventInfo=" + JSON.stringify(cleanInfo(eventInfo))); + +module.addEventExport("a-event", "a-event-exp"); +module.addEventImport("a-event-imp", "module", "base", 0, vif); + +module.validate(); +console.log(module.emitText()); + +module.removeExport("a-event-exp"); +module.removeEvent("a-event"); + +module.validate(); +console.log(module.emitText()); diff --git a/test/binaryen.js/event.js.txt b/test/binaryen.js/event.js.txt new file mode 100644 index 000000000..233f4b037 --- /dev/null +++ b/test/binaryen.js/event.js.txt @@ -0,0 +1,16 @@ +GetEvent is equal: true +getEventInfo={"name":"a-event","module":"","base":"","attribute":0,"type":"vi"} +(module + (type $vi (func (param i32))) + (type $vif (func (param i32 f32))) + (import "module" "base" (event $a-event-imp (attr 0) (param i32 f32))) + (event $a-event (attr 0) (param i32)) + (export "a-event-exp" (event $a-event)) +) + +(module + (type $vi (func (param i32))) + (type $vif (func (param i32 f32))) + (import "module" "base" (event $a-event-imp (attr 0) (param i32 f32))) +) + diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 649abfa4b..e745c0303 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -423,16 +423,22 @@ function test_core() { var initExpr = module.i32.const(1); var global = module.addGlobal("a-global", Binaryen.i32, false, initExpr) + // Create an event + var vi = module.addFunctionType("vi", Binaryen.none, [Binaryen.i32]); + var event_ = module.addEvent("a-event", 0, vi); + // Imports var fiF = module.addFunctionType("fiF", Binaryen.f32, [ Binaryen.i32, Binaryen.f64 ]); module.addFunctionImport("an-imported", "module", "base", fiF); module.addGlobalImport("a-global-imp", "module", "base", Binaryen.i32); + module.addEventImport("a-event-imp", "module", "base", 0, vi); // Exports module.addFunctionExport("kitchen()sinker", "kitchen_sinker"); module.addGlobalExport("a-global", "a-global-exp"); + module.addEventExport("a-event", "a-event-exp"); // Function table. One per module @@ -683,13 +689,16 @@ function test_binaries() { { // create a module and write it to binary module = new Binaryen.Module(); + module.setFeatures(Binaryen.Features.All); var iii = module.addFunctionType("iii", Binaryen.i32, [ Binaryen.i32, Binaryen.i32 ]); + var vii = module.addFunctionType("vii", Binaryen.none, [ Binaryen.i32, Binaryen.i32 ]); var x = module.local.get(0, Binaryen.i32), y = module.local.get(1, Binaryen.i32); var add = module.i32.add(x, y); var adder = module.addFunction("adder", iii, [], add); var initExpr = module.i32.const(3); var global = module.addGlobal("a-global", Binaryen.i32, false, initExpr) + var event_ = module.addEvent("a-event", 0, vii); Binaryen.setDebugInfo(true); // include names section buffer = module.emitBinary(); Binaryen.setDebugInfo(false); @@ -702,6 +711,7 @@ function test_binaries() { // read the module from the binary module = Binaryen.readBinary(buffer); + module.setFeatures(Binaryen.Features.All); // validate, print, and free assert(module.validate()); @@ -755,16 +765,17 @@ function test_parsing() { // create a module and write it to text module = new Binaryen.Module(); - module.setFeatures(Binaryen.Features.All); var iii = module.addFunctionType("iii", Binaryen.i32, [ Binaryen.i32, Binaryen.i32 ]); + var vi = module.addFunctionType("vi", Binaryen.none, [ Binaryen.i32 ]); var x = module.local.get(0, Binaryen.i32), y = module.local.get(1, Binaryen.i32); var add = module.i32.add(x, y); var adder = module.addFunction("adder", iii, [], add); var initExpr = module.i32.const(3); var global = module.addGlobal("a-global", Binaryen.i32, false, initExpr) + var event_ = module.addEvent("a-event", 0, vi); text = module.emitText(); module.dispose(); module = null; @@ -773,6 +784,7 @@ function test_parsing() { text = text.replace('adder', 'ADD_ER'); var module2 = Binaryen.parseText(text); + module2.setFeatures(Binaryen.Features.All); assert(module2.validate()); console.log("module loaded from text form:"); console.log(module2.emitText()); diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 857950e6b..85085fa82 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -63,19 +63,23 @@ getExpressionInfo(f32.const)={"id":14,"type":3,"value":8.5} getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} (module (type $iiIfF (func (param i32 i64 f32 f64) (result i32))) + (type $vi (func (param i32))) (type $fiF (func (param i32 f64) (result f32))) (type $v (func)) - (type $3 (func)) + (type $4 (func)) (import "module" "base" (global $a-global-imp i32)) (import "module" "base" (func $an-imported (param i32 f64) (result f32))) + (import "module" "base" (event $a-event-imp (attr 0) (param i32))) (memory $0 1 256) (data (i32.const 10) "hello, world") (data passive "I am passive") (table $0 1 funcref) (elem (i32.const 0) "$kitchen()sinker") (global $a-global i32 (i32.const 1)) + (event $a-event (attr 0) (param i32)) (export "kitchen_sinker" (func "$kitchen()sinker")) (export "a-global-exp" (global $a-global)) + (export "a-event-exp" (event $a-event)) (export "mem" (memory $0)) (start $starter) (func "$kitchen()sinker" (; 1 ;) (type $iiIfF) (param $0 i32) (param $1 i64) (param $2 f32) (param $3 f64) (result i32) @@ -1898,7 +1902,9 @@ optimized: module loaded from binary form: (module (type $0 (func (param i32 i32) (result i32))) + (type $1 (func (param i32 i32))) (global $global$0 i32 (i32.const 3)) + (event $event$0 (attr 0) (param i32 i32)) (func $adder (; 0 ;) (type $0) (param $0 i32) (param $1 i32) (result i32) (i32.add (local.get $0) @@ -1944,6 +1950,7 @@ int main() { std::map<size_t, BinaryenExpressionRef> expressions; std::map<size_t, BinaryenFunctionRef> functions; std::map<size_t, BinaryenGlobalRef> globals; + std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; BinaryenModuleRef the_module = NULL; @@ -3343,13 +3350,20 @@ getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} expressions[656] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); globals[0] = BinaryenAddGlobal(the_module, "a-global", 1, 0, expressions[656]); { + BinaryenType paramTypes[] = { 1 }; + functionTypes[1] = BinaryenAddFunctionType(the_module, "vi", 0, paramTypes, 1); + } + BinaryenAddEvent(the_module, "a-event", 0, functionTypes[1]); + { BinaryenType paramTypes[] = { 1, 4 }; - functionTypes[1] = BinaryenAddFunctionType(the_module, "fiF", 3, paramTypes, 2); + functionTypes[2] = BinaryenAddFunctionType(the_module, "fiF", 3, paramTypes, 2); } - BinaryenAddFunctionImport(the_module, "an-imported", "module", "base", functionTypes[1]); + BinaryenAddFunctionImport(the_module, "an-imported", "module", "base", functionTypes[2]); BinaryenAddGlobalImport(the_module, "a-global-imp", "module", "base", 1); + BinaryenAddEventImport(the_module, "a-event-imp", "module", "base", 0, functionTypes[1]); exports[0] = BinaryenAddFunctionExport(the_module, "kitchen()sinker", "kitchen_sinker"); exports[1] = BinaryenAddGlobalExport(the_module, "a-global", "a-global-exp"); + exports[2] = BinaryenAddEventExport(the_module, "a-event", "a-event-exp"); BinaryenFunctionGetName(functions[0]); BinaryenFunctionImportGetModule(functions[0]); BinaryenFunctionImportGetBase(functions[0]); @@ -3379,17 +3393,17 @@ getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} } { BinaryenType paramTypes[] = { 0 }; - functionTypes[2] = BinaryenAddFunctionType(the_module, "v", 0, paramTypes, 0); + functionTypes[3] = BinaryenAddFunctionType(the_module, "v", 0, paramTypes, 0); } expressions[658] = BinaryenNop(the_module); { BinaryenType varTypes[] = { 0 }; - functions[1] = BinaryenAddFunction(the_module, "starter", functionTypes[2], varTypes, 0, expressions[658]); + functions[1] = BinaryenAddFunction(the_module, "starter", functionTypes[3], varTypes, 0, expressions[658]); } BinaryenSetStart(the_module, functions[1]); { BinaryenType paramTypes[] = { 0 }; - functionTypes[3] = BinaryenAddFunctionType(the_module, NULL, 0, paramTypes, 0); + functionTypes[4] = BinaryenAddFunctionType(the_module, NULL, 0, paramTypes, 0); } BinaryenModuleAutoDrop(the_module); BinaryenModuleSetFeatures(the_module, 127); @@ -3398,19 +3412,23 @@ getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} BinaryenModulePrint(the_module); (module (type $iiIfF (func (param i32 i64 f32 f64) (result i32))) + (type $vi (func (param i32))) (type $fiF (func (param i32 f64) (result f32))) (type $v (func)) - (type $3 (func)) + (type $4 (func)) (import "module" "base" (global $a-global-imp i32)) (import "module" "base" (func $an-imported (param i32 f64) (result f32))) + (import "module" "base" (event $a-event-imp (attr 0) (param i32))) (memory $0 1 256) (data (i32.const 10) "hello, world") (data passive "I am passive") (table $0 1 funcref) (elem (i32.const 0) "$kitchen()sinker") (global $a-global i32 (i32.const 1)) + (event $a-event (attr 0) (param i32)) (export "kitchen_sinker" (func "$kitchen()sinker")) (export "a-global-exp" (global $a-global)) + (export "a-event-exp" (event $a-event)) (export "mem" (memory $0)) (start $starter) (func "$kitchen()sinker" (; 1 ;) (type $iiIfF) (param $0 i32) (param $1 i64) (param $2 f32) (param $3 f64) (result i32) @@ -4765,6 +4783,7 @@ getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} expressions.clear(); functions.clear(); globals.clear(); + events.clear(); exports.clear(); relooperBlocks.clear(); the_module = BinaryenModuleCreate(); @@ -5706,6 +5725,7 @@ optimized: expressions.clear(); functions.clear(); globals.clear(); + events.clear(); exports.clear(); relooperBlocks.clear(); return 0; @@ -5713,7 +5733,9 @@ optimized: test_parsing text: (module (type $iii (func (param i32 i32) (result i32))) + (type $vi (func (param i32))) (global $a-global i32 (i32.const 3)) + (event $a-event (attr 0) (param i32)) (func $adder (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (i32.add (local.get $0) @@ -5725,7 +5747,9 @@ test_parsing text: module loaded from text form: (module (type $iii (func (param i32 i32) (result i32))) + (type $vi (func (param i32))) (global $a-global i32 (i32.const 3)) + (event $a-event (attr 0) (param i32)) (func $ADD_ER (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (i32.add (local.get $0) diff --git a/test/events.wast b/test/events.wast new file mode 100644 index 000000000..a2c88b977 --- /dev/null +++ b/test/events.wast @@ -0,0 +1,15 @@ +;; Test events + +(module + (event (attr 0) (param i32)) + (event $e (attr 0) (param i32 f32)) + + (event $e-params0 (attr 0) (param i32 f32)) + (event $e-params1 (attr 0) (param i32) (param f32)) + + (event $e-export (export "ex0") (attr 0) (param i32)) + (event $e-import (import "env" "im0") (attr 0) (param i32)) + + (import "env" "im1" (event (attr 0) (param i32 f32))) + (export "ex1" (event $e)) +) diff --git a/test/events.wast.from-wast b/test/events.wast.from-wast new file mode 100644 index 000000000..bcb78f6df --- /dev/null +++ b/test/events.wast.from-wast @@ -0,0 +1,12 @@ +(module + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$vif (func (param i32 f32))) + (import "env" "im0" (event $e-import (attr 0) (param i32))) + (import "env" "im1" (event $import$event1 (attr 0) (param i32 f32))) + (event $2 (attr 0) (param i32)) + (event $e (attr 0) (param i32 f32)) + (event $e-params0 (attr 0) (param i32 f32)) + (event $e-params1 (attr 0) (param i32 f32)) + (event $e-export (attr 0) (param i32)) + (export "ex1" (event $e)) +) diff --git a/test/events.wast.fromBinary b/test/events.wast.fromBinary new file mode 100644 index 000000000..ce19c63bd --- /dev/null +++ b/test/events.wast.fromBinary @@ -0,0 +1,13 @@ +(module + (type $0 (func (param i32))) + (type $1 (func (param i32 f32))) + (import "env" "im0" (event $eimport$0 (attr 0) (param i32))) + (import "env" "im1" (event $eimport$1 (attr 0) (param i32 f32))) + (event $event$0 (attr 0) (param i32)) + (event $event$1 (attr 0) (param i32 f32)) + (event $event$2 (attr 0) (param i32 f32)) + (event $event$3 (attr 0) (param i32 f32)) + (event $event$4 (attr 0) (param i32)) + (export "ex1" (event $event$1)) +) + diff --git a/test/events.wast.fromBinary.noDebugInfo b/test/events.wast.fromBinary.noDebugInfo new file mode 100644 index 000000000..ce19c63bd --- /dev/null +++ b/test/events.wast.fromBinary.noDebugInfo @@ -0,0 +1,13 @@ +(module + (type $0 (func (param i32))) + (type $1 (func (param i32 f32))) + (import "env" "im0" (event $eimport$0 (attr 0) (param i32))) + (import "env" "im1" (event $eimport$1 (attr 0) (param i32 f32))) + (event $event$0 (attr 0) (param i32)) + (event $event$1 (attr 0) (param i32 f32)) + (event $event$2 (attr 0) (param i32 f32)) + (event $event$3 (attr 0) (param i32 f32)) + (event $event$4 (attr 0) (param i32)) + (export "ex1" (event $event$1)) +) + diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index e0b4a5ec4..76a8aa675 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -488,6 +488,11 @@ void test_core() { BinaryenAddGlobal(module, "a-global", BinaryenTypeInt32(), 0, makeInt32(module, 7)); BinaryenAddGlobal(module, "a-mutable-global", BinaryenTypeFloat32(), 1, makeFloat32(module, 7.5)); + // Events + BinaryenType eparams[1] = { BinaryenTypeInt32() }; + BinaryenFunctionTypeRef vi = BinaryenAddFunctionType(module, "vi", BinaryenTypeNone(), eparams, 1); + BinaryenAddEvent(module, "a-event", 0, vi); + // Imports BinaryenType iparams[2] = { BinaryenTypeInt32(), BinaryenTypeFloat64() }; diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index c9bcc4b68..e5e16c6fe 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -21,9 +21,10 @@ BinaryenFeatureAll: 127 ) (module (type $iiIfF (func (param i32 i64 f32 f64) (result i32))) + (type $vi (func (param i32))) (type $fiF (func (param i32 f64) (result f32))) (type $v (func)) - (type $3 (func)) + (type $4 (func)) (import "module" "base" (func $an-imported (param i32 f64) (result f32))) (memory $0 1 256) (data (i32.const 10) "hello, world") @@ -32,6 +33,7 @@ BinaryenFeatureAll: 127 (elem (i32.const 0) "$kitchen()sinker") (global $a-global i32 (i32.const 7)) (global $a-mutable-global (mut f32) (f32.const 7.5)) + (event $a-event (attr 0) (param i32)) (export "kitchen_sinker" (func "$kitchen()sinker")) (export "mem" (memory $0)) (start $starter) @@ -1930,6 +1932,7 @@ int main() { std::map<size_t, BinaryenExpressionRef> expressions; std::map<size_t, BinaryenFunctionRef> functions; std::map<size_t, BinaryenGlobalRef> globals; + std::map<size_t, BinaryenEventRef> events; std::map<size_t, BinaryenExportRef> exports; std::map<size_t, RelooperBlockRef> relooperBlocks; BinaryenModuleRef the_module = NULL; @@ -3308,10 +3311,15 @@ int main() { expressions[654] = BinaryenConst(the_module, BinaryenLiteralFloat32(7.5)); globals[1] = BinaryenAddGlobal(the_module, "a-mutable-global", 3, 1, expressions[654]); { + BinaryenType paramTypes[] = { 1 }; + functionTypes[1] = BinaryenAddFunctionType(the_module, "vi", 0, paramTypes, 1); + } + BinaryenAddEvent(the_module, "a-event", 0, functionTypes[1]); + { BinaryenType paramTypes[] = { 1, 4 }; - functionTypes[1] = BinaryenAddFunctionType(the_module, "fiF", 3, paramTypes, 2); + functionTypes[2] = BinaryenAddFunctionType(the_module, "fiF", 3, paramTypes, 2); } - BinaryenAddFunctionImport(the_module, "an-imported", "module", "base", functionTypes[1]); + BinaryenAddFunctionImport(the_module, "an-imported", "module", "base", functionTypes[2]); exports[0] = BinaryenAddFunctionExport(the_module, "kitchen()sinker", "kitchen_sinker"); BinaryenFunctionGetName(functions[0]); { @@ -3330,17 +3338,17 @@ int main() { } { BinaryenType paramTypes[] = { 0 }; - functionTypes[2] = BinaryenAddFunctionType(the_module, "v", 0, paramTypes, 0); + functionTypes[3] = BinaryenAddFunctionType(the_module, "v", 0, paramTypes, 0); } expressions[656] = BinaryenNop(the_module); { BinaryenType varTypes[] = { 0 }; - functions[1] = BinaryenAddFunction(the_module, "starter", functionTypes[2], varTypes, 0, expressions[656]); + functions[1] = BinaryenAddFunction(the_module, "starter", functionTypes[3], varTypes, 0, expressions[656]); } BinaryenSetStart(the_module, functions[1]); { BinaryenType paramTypes[] = { 0 }; - functionTypes[3] = BinaryenAddFunctionType(the_module, NULL, 0, paramTypes, 0); + functionTypes[4] = BinaryenAddFunctionType(the_module, NULL, 0, paramTypes, 0); } BinaryenModuleAutoDrop(the_module); BinaryenModuleSetFeatures(the_module, 127); @@ -3349,9 +3357,10 @@ int main() { BinaryenModulePrint(the_module); (module (type $iiIfF (func (param i32 i64 f32 f64) (result i32))) + (type $vi (func (param i32))) (type $fiF (func (param i32 f64) (result f32))) (type $v (func)) - (type $3 (func)) + (type $4 (func)) (import "module" "base" (func $an-imported (param i32 f64) (result f32))) (memory $0 1 256) (data (i32.const 10) "hello, world") @@ -3360,6 +3369,7 @@ int main() { (elem (i32.const 0) "$kitchen()sinker") (global $a-global i32 (i32.const 7)) (global $a-mutable-global (mut f32) (f32.const 7.5)) + (event $a-event (attr 0) (param i32)) (export "kitchen_sinker" (func "$kitchen()sinker")) (export "mem" (memory $0)) (start $starter) @@ -4723,6 +4733,7 @@ int main() { expressions.clear(); functions.clear(); globals.clear(); + events.clear(); exports.clear(); relooperBlocks.clear(); the_module = BinaryenModuleCreate(); @@ -5657,6 +5668,7 @@ optimized: expressions.clear(); functions.clear(); globals.clear(); + events.clear(); exports.clear(); relooperBlocks.clear(); return 0; diff --git a/test/example/c-api-kitchen-sink.txt.txt b/test/example/c-api-kitchen-sink.txt.txt index 05edca1a2..679ae534c 100644 --- a/test/example/c-api-kitchen-sink.txt.txt +++ b/test/example/c-api-kitchen-sink.txt.txt @@ -3,9 +3,10 @@ ) (module (type $iiIfF (func (param i32 i64 f32 f64) (result i32))) + (type $vi (func (param i32))) (type $fiF (func (param i32 f64) (result f32))) (type $v (func)) - (type $3 (func)) + (type $4 (func)) (import "module" "base" (func $an-imported (param i32 f64) (result f32))) (memory $0 1 256) (data (i32.const 10) "hello, world") @@ -14,6 +15,7 @@ (elem (i32.const 0) "$kitchen()sinker") (global $a-global i32 (i32.const 7)) (global $a-mutable-global (mut f32) (f32.const 7.5)) + (event $a-event (attr 0) (param i32)) (export "kitchen_sinker" (func "$kitchen()sinker")) (export "mem" (memory $0)) (start $starter) diff --git a/test/metadce/rooted-export.wast b/test/metadce/rooted-export.wast index c2c88ec40..4b93969b4 100644 --- a/test/metadce/rooted-export.wast +++ b/test/metadce/rooted-export.wast @@ -8,5 +8,11 @@ (func $b_wasm_func (unreachable) ) + + (export "wasm_event_a" (event $a_wasm_event)) + (export "wasm_event_b" (event $b_wasm_event)) + + (event $a_wasm_event (attr 0) (param i32)) + (event $b_wasm_event (attr 0) (param i32)) ) diff --git a/test/metadce/rooted-export.wast.dced b/test/metadce/rooted-export.wast.dced index 636be324b..7eef01f40 100644 --- a/test/metadce/rooted-export.wast.dced +++ b/test/metadce/rooted-export.wast.dced @@ -1,6 +1,9 @@ (module (type $FUNCSIG$v (func)) + (type $FUNCSIG$vi (func (param i32))) + (event $b_wasm_event (attr 0) (param i32)) (export "wasm_func_b" (func $b_wasm_func)) + (export "wasm_event_b" (event $b_wasm_event)) (func $b_wasm_func (; 0 ;) (type $FUNCSIG$v) (unreachable) ) diff --git a/test/metadce/rooted-export.wast.dced.stdout b/test/metadce/rooted-export.wast.dced.stdout index 0a0cce75a..5b6a25c02 100644 --- a/test/metadce/rooted-export.wast.dced.stdout +++ b/test/metadce/rooted-export.wast.dced.stdout @@ -1,2 +1,4 @@ -unused: export$wasm_func_a$2 +unused: event$a_wasm_event$2 +unused: export$wasm_event_a$5 +unused: export$wasm_func_a$4 unused: func$a_wasm_func$0 diff --git a/test/metadce/rooted-export.wast.graph.txt b/test/metadce/rooted-export.wast.graph.txt index 274fb0d18..8ecd66dc0 100644 --- a/test/metadce/rooted-export.wast.graph.txt +++ b/test/metadce/rooted-export.wast.graph.txt @@ -1,8 +1,13 @@ [ { - "name": "rooted-export", + "name": "rooted-export-func", "root": true, "export": "wasm_func_b" + }, + { + "name": "rooted-export-event", + "root": true, + "export": "wasm_event_b" } ] diff --git a/test/passes/O3_low-memory-unused_metrics.txt b/test/passes/O3_low-memory-unused_metrics.txt index 91ddf6d87..bf5cd01a8 100644 --- a/test/passes/O3_low-memory-unused_metrics.txt +++ b/test/passes/O3_low-memory-unused_metrics.txt @@ -1,4 +1,5 @@ total + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 0 diff --git a/test/passes/converge_O3_metrics.bin.txt b/test/passes/converge_O3_metrics.bin.txt index dd8470d0d..1c7a3275e 100644 --- a/test/passes/converge_O3_metrics.bin.txt +++ b/test/passes/converge_O3_metrics.bin.txt @@ -1,4 +1,5 @@ total + [events] : 0 [exports] : 2 [funcs] : 8 [globals] : 1 @@ -242,6 +243,7 @@ total ) ) total + [events] : 0 [exports] : 2 [funcs] : 8 [globals] : 1 @@ -486,6 +488,7 @@ total ) ) total + [events] : 0 [exports] : 2 [funcs] : 8 [globals] : 1 diff --git a/test/passes/func-metrics.txt b/test/passes/func-metrics.txt index 83aabc2fe..a6e9b0c92 100644 --- a/test/passes/func-metrics.txt +++ b/test/passes/func-metrics.txt @@ -1,4 +1,5 @@ global + [events] : 0 [exports] : 0 [funcs] : 3 [globals] : 1 @@ -89,6 +90,7 @@ func: ifs ) ) global + [events] : 0 [exports] : 0 [funcs] : 0 [globals] : 0 @@ -97,6 +99,7 @@ global (module ) global + [events] : 0 [exports] : 2 [funcs] : 3 [globals] : 0 @@ -171,6 +174,7 @@ export: b (func_b) ) ) global + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 0 @@ -202,6 +206,7 @@ start: func_a ) ) global + [events] : 0 [exports] : 0 [funcs] : 1 [globals] : 0 @@ -229,6 +234,7 @@ start: func_a ) ) global + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 1 diff --git a/test/passes/metrics.txt b/test/passes/metrics_all-features.txt index 95ca2c601..ba772597d 100644 --- a/test/passes/metrics.txt +++ b/test/passes/metrics_all-features.txt @@ -1,4 +1,5 @@ total + [events] : 2 [exports] : 0 [funcs] : 1 [globals] : 1 @@ -14,11 +15,14 @@ total if : 4 (module (type $0 (func (param i32))) + (type $FUNCSIG$vii (func (param i32 i32))) (memory $0 256 256) (data (i32.const 0) "\ff\ef\0f\1f 0@P\99") (table $0 256 256 funcref) (elem (i32.const 0) $ifs $ifs $ifs) (global $glob i32 (i32.const 1337)) + (event $e0 (attr 0) (param i32)) + (event $e1 (attr 0) (param i32 i32)) (func $ifs (; 0 ;) (type $0) (param $x i32) (local $y f32) (block $block0 @@ -60,6 +64,7 @@ total ) ) total + [events] : 0 [exports] : 0 [funcs] : 0 [globals] : 0 diff --git a/test/passes/metrics.wast b/test/passes/metrics_all-features.wast index 5ae98b7c7..018262f22 100644 --- a/test/passes/metrics.wast +++ b/test/passes/metrics_all-features.wast @@ -5,6 +5,8 @@ (data (i32.const 0) "\ff\ef\0f\1f\20\30\40\50\99") (type $0 (func (param i32))) (global $glob i32 (i32.const 1337)) + (event $e0 (attr 0) (param i32)) + (event $e1 (attr 0) (param i32 i32)) (func $ifs (type $0) (param $x i32) (local $y f32) (block $block0 diff --git a/test/passes/metrics_strip-debug_metrics.bin.txt b/test/passes/metrics_strip-debug_metrics.bin.txt index 3e7294453..51dfd1e79 100644 --- a/test/passes/metrics_strip-debug_metrics.bin.txt +++ b/test/passes/metrics_strip-debug_metrics.bin.txt @@ -1,4 +1,5 @@ total + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 0 @@ -7,6 +8,7 @@ total [vars] : 0 nop : 1 total + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 0 diff --git a/test/passes/metrics_strip-producers_metrics.bin.txt b/test/passes/metrics_strip-producers_metrics.bin.txt index e977d4ed5..290ed2599 100644 --- a/test/passes/metrics_strip-producers_metrics.bin.txt +++ b/test/passes/metrics_strip-producers_metrics.bin.txt @@ -1,4 +1,5 @@ total + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 0 @@ -7,6 +8,7 @@ total [vars] : 0 nop : 1 total + [events] : 0 [exports] : 1 [funcs] : 1 [globals] : 0 diff --git a/test/passes/minify-imports-and-exports.txt b/test/passes/minify-imports-and-exports_all-features.txt index b6a2cf8bf..78852dfa8 100644 --- a/test/passes/minify-imports-and-exports.txt +++ b/test/passes/minify-imports-and-exports_all-features.txt @@ -942,7 +942,7 @@ longname3488 => J9 longname1490 => JA longname4946 => JAa longname1544 => JB -exp1 => JBa +eventname1 => JBa longname1598 => JC longname1652 => JD longname1706 => JE @@ -1035,7 +1035,7 @@ longname3489 => K9 longname1491 => KA longname4947 => KAa longname1545 => KB -exp2 => KBa +exp1 => KBa longname1599 => KC longname1653 => KD longname1707 => KE @@ -1128,6 +1128,7 @@ longname3490 => L9 longname1492 => LA longname4948 => LAa longname1546 => LB +exp2 => LBa longname1600 => LC longname1654 => LD longname1708 => LE @@ -1220,6 +1221,7 @@ longname3491 => M9 longname1493 => MA longname4949 => MAa longname1547 => MB +event1 => MBa longname1601 => MC longname1655 => MD longname1709 => ME @@ -5002,6 +5004,8 @@ longname1426 => zz longname4882 => zza (module (type $FUNCSIG$v (func)) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$vii (func (param i32 i32))) (import "env" "a" (global $import$global0 i32)) (import "env" "__memory_base" (global $import$global1 i32)) (import "env" "__table_base" (global $import$global2 i32)) @@ -10005,8 +10009,11 @@ longname4882 => zza (import "env" "HBa" (func $internal4998)) (import "env" "IBa" (func $internal4999)) (import "other" "anything" (func $internalInfinity)) - (export "JBa" (func $foo1)) - (export "KBa" (func $foo2)) + (import "env" "JBa" (event $eventname1 (attr 0) (param i32))) + (event $event1 (attr 0) (param i32 i32)) + (export "KBa" (func $foo1)) + (export "LBa" (func $foo2)) + (export "MBa" (event $event1)) (func $foo1 (; 5000 ;) (type $FUNCSIG$v) (nop) ) diff --git a/test/passes/minify-imports-and-exports.wast b/test/passes/minify-imports-and-exports_all-features.wast index ce0c46f95..2db91c2ad 100644 --- a/test/passes/minify-imports-and-exports.wast +++ b/test/passes/minify-imports-and-exports_all-features.wast @@ -5002,9 +5002,11 @@ (import "env" "__memory_base" (global i32)) (import "env" "__table_base" (global i32)) (import "other" "anything" (func $internalInfinity)) + (import "env" "eventname1" (event $eventname1 (attr 0) (param i32))) (export "exp1" (func $foo1)) (export "exp2" (func $foo2)) (func $foo1) (func $foo2) + (export "event1" (event $event1)) + (event $event1 (attr 0) (param i32 i32)) ) - diff --git a/test/passes/minify-imports.txt b/test/passes/minify-imports_all-features.txt index 45e295c67..024018bc2 100644 --- a/test/passes/minify-imports.txt +++ b/test/passes/minify-imports_all-features.txt @@ -942,6 +942,7 @@ longname3488 => J9 longname1490 => JA longname4946 => JAa longname1544 => JB +eventname1 => JBa longname1598 => JC longname1652 => JD longname1706 => JE @@ -5000,6 +5001,8 @@ longname1426 => zz longname4882 => zza (module (type $FUNCSIG$v (func)) + (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$vii (func (param i32 i32))) (import "env" "a" (global $import$global0 i32)) (import "env" "__memory_base" (global $import$global1 i32)) (import "env" "__table_base" (global $import$global2 i32)) @@ -10003,8 +10006,11 @@ longname4882 => zza (import "env" "HBa" (func $internal4998)) (import "env" "IBa" (func $internal4999)) (import "other" "anything" (func $internalInfinity)) + (import "env" "JBa" (event $eventname1 (attr 0) (param i32))) + (event $event1 (attr 0) (param i32 i32)) (export "foo1" (func $foo1)) (export "foo2" (func $foo2)) + (export "event1" (event $event1)) (func $foo1 (; 5000 ;) (type $FUNCSIG$v) (nop) ) diff --git a/test/passes/minify-imports.wast b/test/passes/minify-imports_all-features.wast index b24173163..26c8062ba 100644 --- a/test/passes/minify-imports.wast +++ b/test/passes/minify-imports_all-features.wast @@ -5002,9 +5002,11 @@ (import "env" "__memory_base" (global i32)) (import "env" "__table_base" (global i32)) (import "other" "anything" (func $internalInfinity)) + (import "env" "eventname1" (event $eventname1 (attr 0) (param i32))) (export "foo1" (func $foo1)) (export "foo2" (func $foo2)) + (export "event1" (event $event1)) (func $foo1) (func $foo2) + (event $event1 (attr 0) (param i32 i32)) ) - diff --git a/test/passes/remove-unused-module-elements_enable-threads.txt b/test/passes/remove-unused-module-elements_all-features.txt index 5db1ba5e6..3d80f96e9 100644 --- a/test/passes/remove-unused-module-elements_enable-threads.txt +++ b/test/passes/remove-unused-module-elements_all-features.txt @@ -278,3 +278,8 @@ ) ) ) +(module + (type $FUNCSIG$vj (func (param i64))) + (event $e1 (attr 0) (param i64)) + (export "e1" (event $e1)) +) diff --git a/test/passes/remove-unused-module-elements_enable-threads.wast b/test/passes/remove-unused-module-elements_all-features.wast index 8e07fb9c1..3d0248848 100644 --- a/test/passes/remove-unused-module-elements_enable-threads.wast +++ b/test/passes/remove-unused-module-elements_all-features.wast @@ -261,4 +261,11 @@ ) ) ) - +(module ;; non-exported events can be removed + (type $0 (func (param i32))) + (event $e0 (attr 0) (type $0)) + (event $e1 (attr 0) (param i64)) + (export "e1" (event $e1)) + (import "env" "e" (event $e2 (attr 0) (param i32))) + (func $f (; 0 ;) (type $0)) +) diff --git a/test/passes/remove-unused-nonfunction-module-elements_enable-threads.txt b/test/passes/remove-unused-nonfunction-module-elements_all-features.txt index 140cf61e6..e08bf1eb2 100644 --- a/test/passes/remove-unused-nonfunction-module-elements_enable-threads.txt +++ b/test/passes/remove-unused-nonfunction-module-elements_all-features.txt @@ -329,3 +329,12 @@ ) ) ) +(module + (type $0 (func (param i32))) + (type $FUNCSIG$vj (func (param i64))) + (event $e1 (attr 0) (param i64)) + (export "e1" (event $e1)) + (func $f (; 0 ;) (type $0) (param $0 i32) + (nop) + ) +) diff --git a/test/passes/remove-unused-nonfunction-module-elements_enable-threads.wast b/test/passes/remove-unused-nonfunction-module-elements_all-features.wast index 4c1944c12..36bc79e82 100644 --- a/test/passes/remove-unused-nonfunction-module-elements_enable-threads.wast +++ b/test/passes/remove-unused-nonfunction-module-elements_all-features.wast @@ -261,4 +261,11 @@ ) ) ) - +(module ;; non-exported events can be removed + (type $0 (func (param i32))) + (event $e0 (attr 0) (type $0)) + (event $e1 (attr 0) (param i64)) + (export "e1" (event $e1)) + (import "env" "e" (event $e2 (attr 0) (param i32))) + (func $f (; 0 ;) (type $0)) +) diff --git a/test/passes/translate-to-fuzz_all-features.txt b/test/passes/translate-to-fuzz_all-features.txt index fe24e738e..c3fd77b20 100644 --- a/test/passes/translate-to-fuzz_all-features.txt +++ b/test/passes/translate-to-fuzz_all-features.txt @@ -1,33 +1,26 @@ (module (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vifidi (func (param i32 f32 i32 f64 i32))) (type $FUNCSIG$vi (func (param i32))) (type $FUNCSIG$vj (func (param i64))) (type $FUNCSIG$vf (func (param f32))) (type $FUNCSIG$vd (func (param f64))) - (type $FUNCSIG$vjVdddV (func (param i64 v128 f64 f64 f64 v128))) - (type $FUNCSIG$ddVff (func (param f64 v128 f32 f32) (result f64))) - (type $FUNCSIG$VdVjf (func (param f64 v128 i64 f32) (result v128))) - (type $FUNCSIG$v (func)) - (type $FUNCSIG$jjiV (func (param i64 i32 v128) (result i64))) (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) (import "fuzzing-support" "log-i64" (func $log-i64 (param i64))) (import "fuzzing-support" "log-f32" (func $log-f32 (param f32))) (import "fuzzing-support" "log-f64" (func $log-f64 (param f64))) - (memory $0 1 1) + (memory $0 (shared 1 1)) (data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3") - (table $0 8 funcref) - (elem (i32.const 0) $func_6 $func_6 $func_6 $func_6 $func_9 $func_9 $func_9 $func_9) - (global $global$0 (mut i32) (i32.const 975664160)) - (global $global$1 (mut i32) (i32.const -536870912)) - (global $global$2 (mut f32) (f32.const 2147483648)) - (global $global$3 (mut f32) (f32.const 1448959360)) + (table $0 3 3 funcref) + (elem (i32.const 0) $func_5 $func_5 $func_5) + (global $global$0 (mut i32) (i32.const 975663930)) + (global $global$1 (mut i32) (i32.const 2066300474)) + (global $global$2 (mut i64) (i64.const 20510)) + (global $global$3 (mut f32) (f32.const -2147483648)) (global $hangLimit (mut i32) (i32.const 10)) + (event $event$0 (attr 0) (param i32 f32 i32 f64 i32)) (export "hashMemory" (func $hashMemory)) (export "func_5" (func $func_5)) - (export "func_6" (func $func_6)) - (export "func_7" (func $func_7)) - (export "func_7_invoker" (func $func_7_invoker)) - (export "func_9" (func $func_9)) (export "hangLimitInitializer" (func $hangLimitInitializer)) (func $hashMemory (; 4 ;) (type $FUNCSIG$i) (result i32) (local $0 i32) @@ -260,171 +253,18 @@ ) (local.get $0) ) - (func $func_5 (; 5 ;) (type $FUNCSIG$vjVdddV) (param $0 i64) (param $1 v128) (param $2 f64) (param $3 f64) (param $4 f64) (param $5 v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 - (call $log-f64 - (loop $label$1 (result f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$2 (result f64) - (call $log-i32 - (call $hashMemory) - ) - (local.get $2) - ) - ) - ) - (call $log-i32 - (call $hashMemory) - ) - ) - ) - (func $func_6 (; 6 ;) (type $FUNCSIG$ddVff) (param $0 f64) (param $1 v128) (param $2 f32) (param $3 f32) (result f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $0) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 (result f64) - (call $log-i32 - (i32.const 84215045) - ) - (f64.const 8) - ) - ) - (func $func_7 (; 7 ;) (type $FUNCSIG$VdVjf) (param $0 f64) (param $1 v128) (param $2 i64) (param $3 f32) (result v128) - (local $4 i32) - (local $5 f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $1) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (local.tee $1 - (local.tee $1 - (v128.const i32x4 0x6d484708 0x13e740fc 0x5849037f 0xe4000000) - ) - ) - ) - (func $func_7_invoker (; 8 ;) (type $FUNCSIG$v) - (drop - (call $func_7 - (f64.const 16986) - (v128.const i32x4 0x00000000 0x00000010 0xffffe000 0xffffffff) - (i64.const -12) - (f32.const 7243) - ) - ) - (drop - (call $func_7 - (f64.const -65536) - (v128.const i32x4 0x00007d1f 0x00000200 0xffff0000 0x7fffffff) - (i64.const 288230376151711744) - (f32.const 128) - ) - ) - (call $log-i32 - (call $hashMemory) - ) - (drop - (call $func_7 - (f64.const -nan:0xfffffffffffb5) - (v128.const i32x4 0x00000000 0x403a0000 0x00000000 0xb8100000) - (i64.const 66) - (f32.const -nan:0x7fffb0) - ) - ) - ) - (func $func_9 (; 9 ;) (type $FUNCSIG$jjiV) (param $0 i64) (param $1 i32) (param $2 v128) (result i64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $0) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (i64.const 8) - ) - (func $func_10 (; 10 ;) (param $0 v128) (param $1 i64) (param $2 i64) (result v128) + (func $func_5 (; 5 ;) (type $FUNCSIG$vj) (param $0 i64) + (local $1 f64) + (local $2 i32) (local $3 i64) (local $4 v128) - (local $5 f64) - (local $6 f32) - (local $7 v128) - (local $8 f64) - (local $9 i64) - (local $10 f32) - (local $11 i32) - (local $12 f32) - (local $13 i32) - (local $14 v128) - (local $15 v128) - (local $16 f64) + (local $5 f32) (block (if (i32.eqz (global.get $hangLimit) ) - (return - (v128.const i32x4 0x80000000 0x80000001 0xffffffa1 0x00000000) - ) + (return) ) (global.set $hangLimit (i32.sub @@ -434,300 +274,193 @@ ) ) (block $label$0 - (local.set $8 - (f64.const 5382) + (br_if $label$0 + (i32.const 1376786182) ) - (if - (i32.eqz - (local.tee $11 - (loop $label$72 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $15) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (i32.const -127) - ) - ) - ) - (block $label$19 - (block $label$20 - (loop $label$21 - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (v128.const i32x4 0x4598b000 0x4f000000 0x5f000000 0x4d30d0b0) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (nop) - ) - (local.set $11 - (local.tee $13 - (i32.const 3088) - ) - ) - ) - (return - (local.get $0) - ) - ) - (block $label$43 - (loop $label$44 - (block - (if + (local.set $4 + (v128.const i32x4 0x0e0a0e0d 0x0709060c 0x764b6f6f 0x00040000) + ) + (local.set $4 + (if (result v128) + (i32.eqz + (if (result i32) + (if (result i32) (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $4) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block - (block $label$45 - (if - (i32.eqz - (i32.const 536870912) - ) - (local.set $11 - (local.get $13) - ) - (block $label$46 - (global.set $global$3 - (f32.const 269239296) - ) - (local.tee $16 - (local.tee $16 - (block $label$47 - (br $label$46) + (if (result i32) + (i32.eqz + (if + (i32.const 1329942351) + (local.tee $2 + (local.tee $2 + (loop $label$38 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (if + (i32.eqz + (local.get $2) + ) + (block $label$39 + (nop) + (br $label$0) + ) + (block $label$40 + (local.set $4 + (v128.const i32x4 0x05050505 0x46190000 0xc6800000 0x4a031a19) + ) + (br $label$0) + ) + ) + ) + ) + ) + (block $label$41 + (nop) + (br $label$0) ) ) ) + (local.get $2) + (local.get $2) + ) + ) + (block $label$47 + (local.set $2 + (local.get $2) ) + (br $label$0) ) - (loop $label$48 - (block - (if - (i32.eqz - (global.get $hangLimit) + (block $label$48 (result i32) + (loop $label$49 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) ) - (return - (local.get $4) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) ) ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (block + (local.set $5 + (f32.const 9.625223197211503e-38) ) - ) - ) - (block - (local.set $11 - (local.tee $13 - (i32.const 2097152) - ) - ) - (br_if $label$48 - (i32.eqz - (local.tee $11 - (loop $label$49 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $0) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (br_if $label$49 + (if (result i32) + (block $label$57 + (local.set $5 + (local.tee $5 + (block $label$58 (result f32) + (local.set $4 + (local.get $4) + ) + (local.get $5) ) ) ) - (block (result i32) - (local.set $10 - (local.tee $12 - (local.tee $6 - (local.tee $12 - (local.get $12) - ) + (br $label$0) + ) + (if (result i32) + (i32.const 1376786182) + (block $label$60 + (if + (block $label$61 (result i32) + (i32.const 925442358) + ) + (block $label$62 + (br_if $label$62 + (i32.const 256) ) ) - ) - (br_if $label$49 - (i32.const 512) - ) - (loop $label$50 (result i32) - (block + (block $label$63 (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (v128.const i32x4 0x0000002a 0xf801141f 0xfe1c005c 0xf1f27f14) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (local.get $2) + (local.set $1 + (local.get $1) ) - ) - ) - (block $label$51 (result i32) - (local.set $11 - (if (result i32) - (i32.eqz - (if (result i32) - (if (result i32) - (if (result i32) - (i32.eqz - (i32.const 170) - ) - (i32.const 170) - (i32.const 16) - ) - (local.tee $11 - (local.get $13) - ) - (block $label$52 - (local.set $13 - (local.get $11) - ) - (br $label$44) - ) - ) - (block $label$53 - (loop $label$54 - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $14) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block - (nop) - (br_if $label$54 - (i32.eqz - (local.get $13) - ) - ) - (local.set $2 - (i64.const 112) - ) - ) - ) - (br $label$49) + (block $label$67 + (if + (i32.eqz + (i32.const 0) + ) + (block $label$68 + (local.set $1 + (local.get $1) ) - (local.tee $11 - (local.tee $13 - (local.get $11) + (block $label$69 + (nop) + (local.set $4 + (local.get $4) ) ) ) - ) - (block $label$55 (result i32) - (br_if $label$48 - (local.tee $11 - (local.tee $13 - (local.get $13) + (if + (i32.eqz + (br_if $label$48 + (i32.const 32768) + (local.get $2) ) ) - ) - (br_if $label$51 - (local.tee $11 - (local.tee $13 - (i32.const -62) - ) + (local.set $4 + (v128.const i32x4 0xffffff81 0xffffffeb 0x80000000 0x74273131) ) - (if (result i32) - (i32.const 86) - (block $label$56 (result i32) - (br_if $label$56 - (local.get $13) - (i32.const -84) - ) - ) - (loop $label$57 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $14) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (i32.const 34176355) - ) + (local.set $2 + (local.get $2) ) ) ) - (block $label$58 - (local.set $14 - (v128.const i32x4 0x0f0c0d04 0x0a020d43 0x1402026d 0x47130847) - ) - (br $label$49) + (local.set $0 + (i64.const -2097152) ) ) ) - (loop $label$59 + (local.set $1 + (local.get $1) + ) + ) + ) + (br $label$0) + ) + (block $label$70 (result i32) + (loop $label$71 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result i32) + (loop $label$72 (block (if (i32.eqz (global.get $hangLimit) ) - (return - (v128.const i32x4 0x00000000 0x43e00000 0x00000000 0xc1f00000) - ) + (return) ) (global.set $hangLimit (i32.sub @@ -736,16 +469,21 @@ ) ) ) - (block $label$60 - (loop $label$61 + (local.set $4 + (local.tee $4 + (local.get $4) + ) + ) + ) + (br_if $label$71 + (i32.eqz + (loop $label$73 (block (if (i32.eqz (global.get $hangLimit) ) - (return - (v128.const i32x4 0x00007272 0x00000000 0x00000001 0x80000000) - ) + (return) ) (global.set $hangLimit (i32.sub @@ -754,97 +492,127 @@ ) ) ) - (block $label$62 - (local.set $3 - (i64.const -2048) - ) - (i64.store16 offset=3 align=1 - (i32.and - (local.tee $13 - (local.tee $13 - (local.tee $13 - (i32.const 64) - ) - ) - ) - (i32.const 15) - ) - (local.tee $9 - (loop $label$63 (result i64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (v128.const i32x4 0x80000000 0x1e1e141e 0x00008000 0x000e010b) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i64) - (local.set $9 - (local.get $3) - ) - (br_if $label$63 - (i32.const -256) - ) - (block $label$64 (result i64) - (local.set $16 - (f64.const 2147483648) - ) - (local.get $1) - ) - ) - ) - ) + (block $label$74 + (local.set $4 + (v128.const i32x4 0xf8f8ff00 0x000000a5 0x0000000e 0xffff00ff) ) + (br $label$73) ) ) - (return - (local.get $4) - ) ) ) + (i32.const -131072) + ) + ) + ) + ) + (if (result i32) + (local.get $2) + (block $label$75 + (call $log-i32 + (local.tee $2 + (i32.const 5) ) ) + (br $label$49) + ) + (block $label$76 (result i32) + (nop) + (local.tee $2 + (i32.const 1276448839) + ) ) ) ) ) + (local.set $2 + (local.get $2) + ) + ) + ) + (loop $label$90 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) ) - (local.tee $13 - (local.tee $11 - (block $label$65 - (local.set $16 - (f64.const 5.487989131676445e-139) + (block + (local.set $1 + (local.get $1) + ) + (br_if $label$90 + (i32.eqz + (local.tee $2 + (i32.const -93) ) - (br $label$44) ) ) + (nop) ) ) + (local.get $2) ) ) - (local.set $5 - (local.get $5) + (block $label$91 (result i32) + (local.set $5 + (block $label$92 (result f32) + (local.set $1 + (loop $label$19 (result f64) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result f64) + (nop) + (br_if $label$19 + (i32.eqz + (i32.const -129) + ) + ) + (local.tee $1 + (f64.const -nan:0xffffffffffff0) + ) + ) + ) + ) + (local.get $5) + ) + ) + (local.get $2) ) - (local.set $11 - (local.get $11) + (block $label$95 (result i32) + (local.get $2) ) ) ) - (unreachable) + (local.get $4) + (block $label$96 (result v128) + (v128.const i32x4 0x80800000 0xdf800000 0xcf000000 0x4f800000) + ) ) ) ) ) - (func $hangLimitInitializer (; 11 ;) + (func $hangLimitInitializer (; 6 ;) (global.set $hangLimit (i32.const 10) ) diff --git a/test/passes/translate-to-fuzz_all-features.wast b/test/passes/translate-to-fuzz_all-features.wast index 5b378f2b2..ae1761899 100644 --- a/test/passes/translate-to-fuzz_all-features.wast +++ b/test/passes/translate-to-fuzz_all-features.wast @@ -1,4 +1,4 @@ -(module # fake module here, for test harness, but it's really not needed +(module # fake module here, for test harness, but it is really not needed .. any 3INPUT diff --git a/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.txt b/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.txt index 294b4f986..57afb02b7 100644 --- a/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.txt +++ b/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.txt @@ -1,35 +1,24 @@ (module (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vifidi (func (param i32 f32 i32 f64 i32))) (type $FUNCSIG$vi (func (param i32))) (type $FUNCSIG$vj (func (param i64))) (type $FUNCSIG$vf (func (param f32))) (type $FUNCSIG$vd (func (param f64))) - (type $FUNCSIG$vjVdddV (func (param i64 v128 f64 f64 f64 v128))) - (type $FUNCSIG$ddVff (func (param f64 v128 f32 f32) (result f64))) - (type $FUNCSIG$VdVjf (func (param f64 v128 i64 f32) (result v128))) - (type $FUNCSIG$v (func)) - (type $FUNCSIG$jjiV (func (param i64 i32 v128) (result i64))) - (type $FUNCSIG$VVjj (func (param v128 i64 i64) (result v128))) (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) (import "fuzzing-support" "log-i64" (func $log-i64 (param i64))) (import "fuzzing-support" "log-f32" (func $log-f32 (param f32))) (import "fuzzing-support" "log-f64" (func $log-f64 (param f64))) - (memory $0 1 1) + (memory $0 (shared 1 1)) (data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3") - (table $0 8 8 funcref) - (elem (i32.const 0) $func_6 $func_6 $func_6 $func_6 $func_9 $func_9 $func_9 $func_9) - (global $global$0 (mut i32) (i32.const 975664160)) - (global $global$1 (mut i32) (i32.const -536870912)) - (global $global$2 (mut f32) (f32.const 2147483648)) - (global $global$3 (mut f32) (f32.const 1448959360)) + (table $0 0 funcref) + (global $global$0 (mut i32) (i32.const 975663930)) + (global $global$1 (mut i32) (i32.const 2066300474)) + (global $global$2 (mut i64) (i64.const 20510)) + (global $global$3 (mut f32) (f32.const -2147483648)) (global $hangLimit (mut i32) (i32.const 10)) + (event $event$0 (attr 0) (param i32 f32 i32 f64 i32)) (export "hashMemory" (func $hashMemory)) - (export "func_5" (func $func_5)) - (export "func_6" (func $func_6)) - (export "func_7" (func $func_7)) - (export "func_7_invoker" (func $func_7_invoker)) - (export "func_9" (func $func_9)) - (export "func_10" (func $func_10)) (export "hangLimitInitializer" (func $hangLimitInitializer)) (func $hashMemory (; 4 ;) (type $FUNCSIG$i) (result i32) (local $0 i32) @@ -262,7 +251,12 @@ ) (local.get $0) ) - (func $func_5 (; 5 ;) (type $FUNCSIG$vjVdddV) (param $0 i64) (param $1 v128) (param $2 f64) (param $3 f64) (param $4 f64) (param $5 v128) + (func $func_5 (; 5 ;) (param $0 i64) + (local $1 f64) + (local $2 i32) + (local $3 i64) + (local $4 v128) + (local $5 f32) (block (if (i32.eqz @@ -278,173 +272,612 @@ ) ) (block $label$0 - (call $log-f64 - (loop $label$1 (result f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (br_if $label$0 + (i32.eqz + (local.tee $2 + (local.tee $2 + (local.tee $2 + (local.tee $2 + (local.get $2) + ) ) ) ) - (block $label$2 (result f64) - (call $log-i32 - (call $hashMemory) - ) - (local.get $2) - ) - ) - ) - (call $log-i32 - (call $hashMemory) - ) - ) - ) - (func $func_6 (; 6 ;) (type $FUNCSIG$ddVff) (param $0 f64) (param $1 v128) (param $2 f32) (param $3 f32) (result f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $0) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 (result f64) - (call $log-i32 - (i32.const 84215045) - ) - (f64.const 8) - ) - ) - (func $func_7 (; 7 ;) (type $FUNCSIG$VdVjf) (param $0 f64) (param $1 v128) (param $2 i64) (param $3 f32) (result v128) - (local $4 i32) - (local $5 f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $1) ) ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (local.tee $1 - (local.tee $1 - (v128.const i32x4 0x6d484708 0x13e740fc 0x5849037f 0xe4000000) - ) - ) - ) - (func $func_7_invoker (; 8 ;) (type $FUNCSIG$v) - (drop - (call $func_7 - (f64.const 16986) - (v128.const i32x4 0x00000000 0x00000010 0xffffe000 0xffffffff) - (i64.const -12) - (f32.const 7243) - ) - ) - (drop - (call $func_7 - (f64.const -65536) - (v128.const i32x4 0x00007d1f 0x00000200 0xffff0000 0x7fffffff) - (i64.const 288230376151711744) - (f32.const 128) - ) - ) - (call $log-i32 - (call $hashMemory) - ) - (drop - (call $func_7 - (f64.const 0) - (v128.const i32x4 0x00000000 0x403a0000 0x00000000 0xb8100000) - (i64.const 66) - (f32.const 0) - ) - ) - ) - (func $func_9 (; 9 ;) (type $FUNCSIG$jjiV) (param $0 i64) (param $1 i32) (param $2 v128) (result i64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $0) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (i64.const 8) - ) - (func $func_10 (; 10 ;) (type $FUNCSIG$VVjj) (param $0 v128) (param $1 i64) (param $2 i64) (result v128) - (local $3 i64) - (local $4 v128) - (local $5 f64) - (local $6 f32) - (local $7 v128) - (local $8 f64) - (local $9 i64) - (local $10 f32) - (local $11 i32) - (local $12 f32) - (local $13 i32) - (local $14 v128) - (local $15 v128) - (local $16 f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $14) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (local.set $4 + (v128.const i32x4 0x0e0a0e0d 0x0709060c 0x764b6f6f 0x00040000) + ) + (local.set $4 + (if (result v128) + (i32.eqz + (if (result i32) + (if (result i32) + (i32.eqz + (if (result i32) + (i32.eqz + (if + (i32.eqz + (if (result i32) + (i32.eqz + (if (result i32) + (i32.eqz + (if (result i32) + (local.get $2) + (loop $label$1 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result i32) + (block $label$2 + (local.set $3 + (i64.const 15662) + ) + (local.set $2 + (local.get $2) + ) + ) + (br_if $label$1 + (local.get $2) + ) + (if (result i32) + (i32.eqz + (local.get $2) + ) + (local.get $2) + (local.get $2) + ) + ) + ) + (block $label$3 (result i32) + (local.tee $2 + (i32.const 286267661) + ) + ) + ) + ) + (block $label$4 + (loop $label$5 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block + (block $label$6 + (if + (i32.eqz + (loop $label$7 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (i32.const 6506) + ) + ) + (block $label$8 + (local.set $2 + (local.tee $2 + (local.get $2) + ) + ) + (local.set $5 + (local.get $5) + ) + ) + (block $label$9 + (if + (local.tee $2 + (if (result i32) + (local.get $2) + (local.get $2) + (loop $label$10 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result i32) + (nop) + (br_if $label$10 + (i32.eqz + (i32.const 64) + ) + ) + (local.tee $2 + (loop $label$11 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (i32.const 512) + ) + ) + ) + ) + ) + ) + (local.set $3 + (local.get $3) + ) + (loop $label$12 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (local.set $1 + (local.get $1) + ) + ) + ) + (local.set $2 + (i32.const 170) + ) + ) + ) + (call $log-i32 + (local.get $2) + ) + ) + (br_if $label$5 + (i32.eqz + (i32.const 2376257) + ) + ) + (local.set $4 + (local.tee $4 + (v128.const i32x4 0xfff70000 0x007f700e 0x07420400 0x8000007f) + ) + ) + ) + ) + (block $label$13 + (if + (i32.eqz + (block $label$14 (result i32) + (local.set $4 + (v128.const i32x4 0x80000000 0x00000080 0xfffffffc 0x00007fff) + ) + (i32.const -123) + ) + ) + (local.set $1 + (local.get $1) + ) + (local.set $5 + (local.get $5) + ) + ) + (br $label$0) + ) + ) + (block $label$17 (result i32) + (i64.atomic.store offset=3 + (i32.const 640629291) + (local.tee $0 + (i64.const -16) + ) + ) + (if (result i32) + (block $label$18 + (local.set $1 + (loop $label$19 (result f64) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result f64) + (nop) + (br_if $label$19 + (i32.eqz + (local.get $2) + ) + ) + (local.tee $1 + (f64.const 0) + ) + ) + ) + ) + (return) + ) + (local.tee $2 + (local.get $2) + ) + (block $label$20 + (loop $label$21 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (local.set $1 + (local.get $1) + ) + ) + (return) + ) + ) + ) + ) + ) + (block $label$22 (result i32) + (local.set $5 + (f32.const 10160664) + ) + (if (result i32) + (i32.eqz + (i32.const 0) + ) + (block $label$23 + (local.set $1 + (loop $label$24 (result f64) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result f64) + (local.set $3 + (local.get $0) + ) + (br_if $label$24 + (i32.const -9) + ) + (f64.const -18446744073709551615) + ) + ) + ) + (br $label$0) + ) + (block $label$25 (result i32) + (loop $label$26 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block + (local.set $2 + (local.get $2) + ) + (br_if $label$26 + (i32.eqz + (if (result i32) + (br_if $label$25 + (i32.const -8) + (local.get $2) + ) + (local.get $2) + (block $label$29 (result i32) + (call $log-i32 + (call $hashMemory) + ) + (loop $label$30 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (local.get $2) + ) + ) + ) + ) + ) + (local.set $5 + (local.get $5) + ) + ) + ) + (local.get $2) + ) + ) + ) + (block $label$35 + (local.set $1 + (f64.const 1414944843) + ) + (br $label$0) + ) + ) + ) + (local.tee $2 + (local.tee $2 + (loop $label$38 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (if + (i32.eqz + (local.get $2) + ) + (block $label$39 + (nop) + (br $label$0) + ) + (block $label$40 + (local.set $1 + (local.get $1) + ) + (br $label$0) + ) + ) + ) + ) + ) + (block $label$41 + (memory.copy + (loop $label$42 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (if (result i32) + (loop $label$43 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$44 (result i32) + (local.set $3 + (i64.const 2097574720517510216) + ) + (if (result i32) + (i32.eqz + (local.get $2) + ) + (i32.const 1296450369) + (local.tee $2 + (i32.const -14) + ) + ) + ) + ) + (block $label$45 + (local.set $2 + (i32.const 235407412) + ) + (br $label$0) + ) + (block $label$46 (result i32) + (local.set $2 + (local.tee $2 + (local.tee $2 + (local.tee $2 + (i32.const 1179009606) + ) + ) + ) + ) + (i32.const 1073741824) + ) + ) + ) + (local.get $2) + (i32.const 1073741824) + ) + (return) + ) + ) + ) + (local.get $2) + (local.get $2) + ) + ) + (block $label$47 + (local.set $2 + (local.get $2) + ) + (br $label$0) + ) + (block $label$48 (result i32) + (loop $label$49 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (local.set $5 + (local.get $5) + ) + ) + (loop $label$90 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block + (local.set $1 + (local.get $1) + ) + (local.set $2 + (local.get $2) + ) + (nop) + ) + ) + (local.get $2) + ) + ) + (block $label$91 (result i32) + (local.set $5 + (block $label$92 (result f32) + (f32.const 6) + ) + ) + (local.get $2) + ) + (local.get $2) + ) + ) + (v128.const i32x4 0xffffffc0 0x00001f16 0x00008000 0x505c1a13) + (v128.const i32x4 0xc7007b11 0x721d0901 0x01810043 0x441f1201) ) ) ) - (return - (local.get $14) - ) ) - (func $hangLimitInitializer (; 11 ;) + (func $hangLimitInitializer (; 6 ;) (global.set $hangLimit (i32.const 10) ) ) - (func $deNan32 (; 12 ;) (param $0 f32) (result f32) + (func $deNan32 (; 7 ;) (param $0 f32) (result f32) (if (result f32) (f32.eq (local.get $0) @@ -454,7 +887,7 @@ (f32.const 0) ) ) - (func $deNan64 (; 13 ;) (param $0 f64) (result f64) + (func $deNan64 (; 8 ;) (param $0 f64) (result f64) (if (result f64) (f64.eq (local.get $0) diff --git a/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.wast b/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.wast index cbf25fde1..3dab8874e 100644 --- a/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.wast +++ b/test/passes/translate-to-fuzz_no-fuzz-nans_all-features.wast @@ -1,4 +1,4 @@ -(module # fake module here, for test harness, but it's really not needed +(module # fake module here, for test harness, but it is really not needed .. any 3INPUT diff --git a/test/spec/events.wast b/test/spec/events.wast new file mode 100644 index 000000000..80a6b11fe --- /dev/null +++ b/test/spec/events.wast @@ -0,0 +1,43 @@ +;; Test events + +(module + (event (attr 0) (param i32)) + (event $e (attr 0) (param i32 f32)) + + (event $e-params0 (attr 0) (param i32 f32)) + (event $e-params1 (attr 0) (param i32) (param f32)) + + (event $e-export (export "ex0") (attr 0) (param i32)) + (event $e-import (import "env" "im0") (attr 0) (param i32)) + + (import "env" "im1" (event (attr 0) (param i32 f32))) + (export "ex1" (event $e)) +) + +(assert_invalid + (module (event $e (attr 0) (param i32) (result i32))) + "Event type's result type should be none" +) + +(assert_invalid + (module (event $e (attr 0))) + "There should be 1 or more values in an event type" +) + +(assert_invalid + (module (event $e (attr 1) (param i32))) + "Currently only attribute 0 is supported" +) + +(assert_invalid + (module (event $e (attr 0) (param except_ref))) + "Values in an event should have integer or float type" +) + +(assert_invalid + (module + (type $t (param i32)) + (event $e (attr 0) (type $t) (param i32 f32)) + "type and param don't match" + ) +) |