summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp18
-rw-r--r--src/binaryen-c.h9
-rw-r--r--src/gen-s-parser.inc14
-rw-r--r--src/ir/ReFinalize.cpp1
-rw-r--r--src/ir/cost.h1
-rw-r--r--src/ir/effects.h1
-rw-r--r--src/js/binaryen.js-post.js19
-rw-r--r--src/passes/Print.cpp4
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp1
-rw-r--r--src/tools/wasm-ctor-eval.cpp4
-rw-r--r--src/wasm-binary.h3
-rw-r--r--src/wasm-builder.h6
-rw-r--r--src/wasm-delegations-fields.def6
-rw-r--r--src/wasm-delegations.def1
-rw-r--r--src/wasm-interpreter.h13
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm.h11
-rw-r--r--src/wasm/wasm-binary.cpp24
-rw-r--r--src/wasm/wasm-s-parser.cpp9
-rw-r--r--src/wasm/wasm-stack.cpp5
-rw-r--r--src/wasm/wasm-validator.cpp9
-rw-r--r--src/wasm/wasm.cpp4
-rw-r--r--src/wasm2js.h4
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");