diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 18 | ||||
-rw-r--r-- | src/binaryen-c.h | 9 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 14 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/cost.h | 1 | ||||
-rw-r--r-- | src/ir/effects.h | 1 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 19 | ||||
-rw-r--r-- | src/passes/Print.cpp | 4 | ||||
-rw-r--r-- | src/passes/RemoveUnusedModuleElements.cpp | 1 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 4 | ||||
-rw-r--r-- | src/wasm-binary.h | 3 | ||||
-rw-r--r-- | src/wasm-builder.h | 6 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 6 | ||||
-rw-r--r-- | src/wasm-delegations.def | 1 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 13 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm.h | 11 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 24 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 9 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 5 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 9 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 4 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
23 files changed, 162 insertions, 6 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index ef6c3abdd..49f453715 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1305,6 +1305,12 @@ BinaryenExpressionRef BinaryenTableSet(BinaryenModuleRef module, .makeTableSet(name, (Expression*)index, (Expression*)value)); } +BinaryenExpressionRef BinaryenTableSize(BinaryenModuleRef module, + const char* name) { + return static_cast<Expression*>( + Builder(*(Module*)module).makeTableSize(name)); +} + BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, const char* name, BinaryenExpressionRef body, @@ -1950,6 +1956,18 @@ void BinaryenTableSetSetValue(BinaryenExpressionRef expr, assert(valueExpr); static_cast<TableSet*>(expression)->value = (Expression*)valueExpr; } +// TableSize +const char* BinaryenTableSizeGetTable(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is<TableSize>()); + return static_cast<TableSize*>(expression)->table.c_str(); +} +void BinaryenTableSetSizeTable(BinaryenExpressionRef expr, const char* table) { + auto* expression = (Expression*)expr; + assert(expression->is<TableSize>()); + assert(table); + static_cast<TableSize*>(expression)->table = table; +} // MemoryGrow BinaryenExpressionRef BinaryenMemoryGrowGetDelta(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; diff --git a/src/binaryen-c.h b/src/binaryen-c.h index d9e1afc8e..3d57aca75 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -860,6 +860,8 @@ BinaryenTableSet(BinaryenModuleRef module, const char* name, BinaryenExpressionRef index, BinaryenExpressionRef value); +BINARYEN_API BinaryenExpressionRef BinaryenTableSize(BinaryenModuleRef module, + const char* name); // Try: name can be NULL. delegateTarget should be NULL in try-catch. BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, @@ -1238,6 +1240,13 @@ BinaryenTableSetGetValue(BinaryenExpressionRef expr); BINARYEN_API void BinaryenTableSetSetValue(BinaryenExpressionRef expr, BinaryenExpressionRef valueExpr); +// TableSize + +// Gets the name of the table being accessed by a `table.size` expression. +BINARYEN_API const char* BinaryenTableSizeGetTable(BinaryenExpressionRef expr); +// Sets the name of the table being accessed by a `table.size` expression. +BINARYEN_API void BinaryenTableSizeSetTable(BinaryenExpressionRef expr, + const char* table); // MemoryGrow // Gets the delta of a `memory.grow` expression. diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index cca1c3445..0d61244fd 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -3046,9 +3046,17 @@ switch (op[0]) { case 'g': if (strcmp(op, "table.get") == 0) { return makeTableGet(s); } goto parse_error; - case 's': - if (strcmp(op, "table.set") == 0) { return makeTableSet(s); } - goto parse_error; + case 's': { + switch (op[7]) { + case 'e': + if (strcmp(op, "table.set") == 0) { return makeTableSet(s); } + goto parse_error; + case 'i': + if (strcmp(op, "table.size") == 0) { return makeTableSize(s); } + goto parse_error; + default: goto parse_error; + } + } default: goto parse_error; } } diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 0d107a759..a9cf8050d 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -137,6 +137,7 @@ void ReFinalize::visitRefFunc(RefFunc* curr) { void ReFinalize::visitRefEq(RefEq* curr) { curr->finalize(); } void ReFinalize::visitTableGet(TableGet* curr) { curr->finalize(); } void ReFinalize::visitTableSet(TableSet* curr) { curr->finalize(); } +void ReFinalize::visitTableSize(TableSize* curr) { curr->finalize(); } void ReFinalize::visitTry(Try* curr) { curr->finalize(); } void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); } void ReFinalize::visitRethrow(Rethrow* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index 7cf0de926..7c18a8200 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -544,6 +544,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> { CostType visitTableSet(TableSet* curr) { return 2 + visit(curr->index) + visit(curr->value); } + CostType visitTableSize(TableSize* curr) { return 1; } CostType visitTry(Try* curr) { // We assume no exception will be thrown in most cases return visit(curr->body); diff --git a/src/ir/effects.h b/src/ir/effects.h index 44b2cba94..3ccffb6f5 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -526,6 +526,7 @@ private: parent.writesMemory = true; parent.implicitTrap = true; } + void visitTableSize(TableSize* curr) { parent.readsTable = true; } void visitConst(Const* curr) {} void visitUnary(Unary* curr) { switch (curr->op) { diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 8fbd2b7ec..29729c4b1 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -93,6 +93,7 @@ function initializeConstants() { 'RefEq', 'TableGet', 'TableSet', + 'TableSize', 'Try', 'Throw', 'Rethrow', @@ -671,6 +672,9 @@ function wrapModule(module, self = {}) { }, 'set'(name, index, value) { return Module['_BinaryenTableSet'](module, strToStack(name), index, value); + }, + 'size'(name) { + return Module['_BinaryenTableSize'](module, strToStack(name)); } } @@ -2825,6 +2829,12 @@ Module['getExpressionInfo'] = function(expr) { 'index': Module['_BinaryenTableSetGetIndex'](expr), 'value': Module['_BinaryenTableSetGetValue'](expr) }; + case Module['TableSizeId']: + return { + 'id': id, + 'type': type, + 'table': UTF8ToString(Module['_BinaryenTableSizeGetTable'](expr)), + }; case Module['LoadId']: return { 'id': id, @@ -3831,6 +3841,15 @@ Module['TableSet'] = makeExpressionWrapper({ } }); +Module['TableSize'] = makeExpressionWrapper({ + 'getTable'(expr) { + return UTF8ToString(Module['_BinaryenTableSizeGetTable'](expr)); + }, + 'setTable'(expr, name) { + preserveStack(() => { Module['_BinaryenTableSizeSetTable'](expr, strToStack(name)) }); + }, +}); + Module['MemorySize'] = makeExpressionWrapper({}); Module['MemoryGrow'] = makeExpressionWrapper({ diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index bea704b1d..abea90117 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1852,6 +1852,10 @@ struct PrintExpressionContents printMedium(o, "table.set "); printName(curr->table, o); } + void visitTableSize(TableSize* curr) { + printMedium(o, "table.size "); + printName(curr->table, o); + } void visitTry(Try* curr) { printMedium(o, "try"); if (curr->name.is()) { diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 32db977ec..0f2c69e02 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -130,6 +130,7 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { } void visitTableGet(TableGet* curr) { maybeAddTable(curr->table); } void visitTableSet(TableSet* curr) { maybeAddTable(curr->table); } + void visitTableSize(TableSize* curr) { maybeAddTable(curr->table); } void visitThrow(Throw* curr) { maybeAdd(ModuleElement(ModuleElementKind::Tag, curr->tag)); } diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index a0ae99a8b..189ce9f71 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -351,6 +351,10 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface { throw FailToEvalException("table.set: TODO"); } + Literal tableSize(Name tableName) { + throw FailToEvalException("table.size: TODO"); + } + int8_t load8s(Address addr) override { return doLoad<int8_t>(addr); } uint8_t load8u(Address addr) override { return doLoad<uint8_t>(addr); } int16_t load16s(Address addr) override { return doLoad<int16_t>(addr); } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index b211c536c..ae2dd4656 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1025,6 +1025,7 @@ enum ASTNodes { // reference types opcodes + TableSize = 0x10, RefNull = 0xd0, RefIsNull = 0xd1, RefFunc = 0xd2, @@ -1635,6 +1636,7 @@ public: bool maybeVisitDataDrop(Expression*& out, uint32_t code); bool maybeVisitMemoryCopy(Expression*& out, uint32_t code); bool maybeVisitMemoryFill(Expression*& out, uint32_t code); + bool maybeVisitTableSize(Expression*& out, uint32_t code); bool maybeVisitI31New(Expression*& out, uint32_t code); bool maybeVisitI31Get(Expression*& out, uint32_t code); bool maybeVisitRefTest(Expression*& out, uint32_t code); @@ -1664,6 +1666,7 @@ public: void visitRefEq(RefEq* curr); void visitTableGet(TableGet* curr); void visitTableSet(TableSet* curr); + void visitTableSize(TableSize* curr); void visitTryOrTryInBlock(Expression*& out); void visitThrow(Throw* curr); void visitRethrow(Rethrow* curr); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 467edf1bd..87167877a 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -664,6 +664,12 @@ public: ret->finalize(); return ret; } + TableSize* makeTableSize(Name table) { + auto* ret = wasm.allocator.alloc<TableSize>(); + ret->table = table; + ret->finalize(); + return ret; + } private: Try* makeTry(Name name, diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index b6828fbc2..90ab03f49 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -516,6 +516,12 @@ switch (DELEGATE_ID) { DELEGATE_END(TableSet); break; } + case Expression::Id::TableSizeId: { + DELEGATE_START(TableSize); + DELEGATE_FIELD_NAME(TableSet, table); + DELEGATE_END(TableSize); + break; + } case Expression::Id::TryId: { DELEGATE_START(Try); DELEGATE_FIELD_SCOPE_NAME_USE(Try, delegateTarget); diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def index c040dd551..8d162dd90 100644 --- a/src/wasm-delegations.def +++ b/src/wasm-delegations.def @@ -60,6 +60,7 @@ DELEGATE(RefFunc); DELEGATE(RefEq); DELEGATE(TableGet); DELEGATE(TableSet); +DELEGATE(TableSize); DELEGATE(Try); DELEGATE(Throw); DELEGATE(Rethrow); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 2952869c6..2179c4923 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1360,6 +1360,7 @@ public: } Flow visitTableGet(TableGet* curr) { WASM_UNREACHABLE("unimp"); } Flow visitTableSet(TableSet* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitTableSize(TableSize* curr) { WASM_UNREACHABLE("unimp"); } Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); } Flow visitThrow(Throw* curr) { NOTE_ENTER("Throw"); @@ -2167,6 +2168,10 @@ public: NOTE_ENTER("TableSet"); return Flow(NONCONSTANT_FLOW); } + Flow visitTableSize(TableSize* curr) { + NOTE_ENTER("TableSize"); + return Flow(NONCONSTANT_FLOW); + } Flow visitLoad(Load* curr) { NOTE_ENTER("Load"); return Flow(NONCONSTANT_FLOW); @@ -2798,7 +2803,6 @@ private: return info.interface->tableLoad(info.name, index.getSingleValue().geti32()); } - Flow visitTableSet(TableSet* curr) { NOTE_ENTER("TableSet"); Flow index = this->visit(curr->index); @@ -2815,6 +2819,13 @@ private: return Flow(); } + Flow visitTableSize(TableSize* curr) { + NOTE_ENTER("TableSize"); + auto table = instance.wasm.getTable(curr->table); + // TODO: properly handle table size when TableGrow exists + return Literal::makeFromInt32(table->initial, Type::i32); + } + Flow visitLocalGet(LocalGet* curr) { NOTE_ENTER("LocalGet"); auto index = curr->index; diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 942eae19b..f5be7924f 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -267,6 +267,7 @@ private: Expression* makeRefEq(Element& s); Expression* makeTableGet(Element& s); Expression* makeTableSet(Element& s); + Expression* makeTableSize(Element& s); Expression* makeTry(Element& s); Expression* makeTryOrCatchBody(Element& s, Type type, bool isTry); Expression* makeThrow(Element& s); diff --git a/src/wasm.h b/src/wasm.h index c87b8c197..197b8bd84 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -629,6 +629,7 @@ public: RefEqId, TableGetId, TableSetId, + TableSizeId, TryId, ThrowId, RethrowId, @@ -1301,6 +1302,16 @@ public: void finalize(); }; +class TableSize : public SpecificExpression<Expression::TableSizeId> { +public: + TableSize() { type = Type::i32; } + TableSize(MixedArena& allocator) : TableSize() {} + + Name table; + + void finalize(); +}; + class Try : public SpecificExpression<Expression::TryId> { public: Try(MixedArena& allocator) : catchTags(allocator), catchBodies(allocator) {} diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 7e72b056f..9aa18f270 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2793,6 +2793,8 @@ void WasmBinaryBuilder::processNames() { get->table = getTableName(index); } else if (auto* set = ref->dynCast<TableSet>()) { set->table = getTableName(index); + } else if (auto* size = ref->dynCast<TableSize>()) { + size->table = getTableName(index); } else { WASM_UNREACHABLE("Invalid type in table references"); } @@ -3613,8 +3615,10 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitMemoryFill(curr, opcode)) { break; } - throwError("invalid code after nontrapping float-to-int prefix: " + - std::to_string(opcode)); + if (maybeVisitTableSize(curr, opcode)) { + break; + } + throwError("invalid code after misc prefix: " + std::to_string(opcode)); break; } case BinaryConsts::SIMDPrefix: { @@ -4918,6 +4922,22 @@ bool WasmBinaryBuilder::maybeVisitMemoryFill(Expression*& out, uint32_t code) { return true; } +bool WasmBinaryBuilder::maybeVisitTableSize(Expression*& out, uint32_t code) { + if (code != BinaryConsts::TableSize) { + return false; + } + Index tableIdx = getU32LEB(); + if (tableIdx >= tables.size()) { + throwError("bad table index"); + } + auto* curr = allocator.alloc<TableSize>(); + curr->finalize(); + // Defer setting the table name for later, when we know it. + tableRefs[tableIdx].push_back(curr); + out = curr; + return true; +} + bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) { Binary* curr; #define INT_TYPED_CODE(code) \ diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 854228e9f..6c41264a6 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2462,6 +2462,15 @@ Expression* SExpressionWasmBuilder::makeTableSet(Element& s) { return Builder(wasm).makeTableSet(tableName, index, value); } +Expression* SExpressionWasmBuilder::makeTableSize(Element& s) { + auto tableName = s[1]->str(); + auto* table = wasm.getTableOrNull(tableName); + if (!table) { + throw ParseException("invalid table name in table.size", s.line, s.col); + } + return Builder(wasm).makeTableSize(tableName); +} + // try can be either in the form of try-catch or try-delegate. // try-catch is written in the folded wast format as // (try diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 8f6581956..f81a0b7a0 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -1857,6 +1857,11 @@ void BinaryInstWriter::visitTableSet(TableSet* curr) { o << U32LEB(parent.getTableIndex(curr->table)); } +void BinaryInstWriter::visitTableSize(TableSize* curr) { + o << int8_t(BinaryConsts::MiscPrefix) << U32LEB(BinaryConsts::TableSize); + o << U32LEB(parent.getTableIndex(curr->table)); +} + void BinaryInstWriter::visitTry(Try* curr) { breakStack.push_back(curr->name); o << int8_t(BinaryConsts::Try); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 0e362df9c..0271884a4 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -366,6 +366,7 @@ public: void visitRefEq(RefEq* curr); void visitTableGet(TableGet* curr); void visitTableSet(TableSet* curr); + void visitTableSize(TableSize* curr); void noteDelegate(Name name, Expression* curr); void noteRethrow(Name name, Expression* curr); void visitTry(Try* curr); @@ -2063,6 +2064,14 @@ void FunctionValidator::visitTableSet(TableSet* curr) { } } +void FunctionValidator::visitTableSize(TableSize* curr) { + shouldBeTrue(getModule()->features.hasReferenceTypes(), + curr, + "table.size requires reference types to be enabled"); + auto* table = getModule()->getTableOrNull(curr->table); + shouldBeTrue(!!table, curr, "table.size table must exist"); +} + void FunctionValidator::noteDelegate(Name name, Expression* curr) { if (name != DELEGATE_CALLER_TARGET) { shouldBeTrue(delegateTargetNames.count(name) != 0, diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 4975f4597..c42a1089d 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -857,6 +857,10 @@ void TableSet::finalize() { } } +void TableSize::finalize() { + // Nothing to do - the type must have been set already during construction. +} + void Try::finalize() { // If none of the component bodies' type is a supertype of the others, assume // the current type is already correct. TODO: Calculate a proper LUB. diff --git a/src/wasm2js.h b/src/wasm2js.h index ac7e94421..03d1fd1da 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2175,6 +2175,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } + Ref visitTableSize(TableSize* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } Ref visitTry(Try* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); |