diff options
Diffstat (limited to 'src/wasm/wasm-s-parser.cpp')
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 161 |
1 files changed, 118 insertions, 43 deletions
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 0dc121f2c..bcce3993e 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -458,6 +458,19 @@ Name SExpressionWasmBuilder::getFunctionName(Element& s) { } } +Name SExpressionWasmBuilder::getTableName(Element& s) { + if (s.dollared()) { + return s.str(); + } else { + // index + size_t offset = atoi(s.str().c_str()); + if (offset >= tableNames.size()) { + throw ParseException("unknown table in getTableName", s.line, s.col); + } + return tableNames[offset]; + } +} + Name SExpressionWasmBuilder::getGlobalName(Element& s) { if (s.dollared()) { return s.str(); @@ -1828,11 +1841,16 @@ Expression* SExpressionWasmBuilder::makeCall(Element& s, bool isReturn) { Expression* SExpressionWasmBuilder::makeCallIndirect(Element& s, bool isReturn) { - if (!wasm.table.exists) { - throw ParseException("no table", s.line, s.col); + if (wasm.tables.empty()) { + throw ParseException("no tables", s.line, s.col); } Index i = 1; auto ret = allocator.alloc<CallIndirect>(); + if (s[i]->isStr()) { + ret->table = s[i++]->str(); + } else { + ret->table = wasm.tables.front()->name; + } i = parseTypeUse(s, i, ret->sig); parseCallOperands(s, i, s.size() - 1, ret); ret->target = parseExpression(s[s.size() - 1]); @@ -2464,17 +2482,21 @@ void SExpressionWasmBuilder::parseExport(Element& s) { ex->name = s[1]->str(); if (s[2]->isList()) { auto& inner = *s[2]; - ex->value = inner[1]->str(); if (elementStartsWith(inner, FUNC)) { ex->kind = ExternalKind::Function; + ex->value = getFunctionName(*inner[1]); } else if (elementStartsWith(inner, MEMORY)) { ex->kind = ExternalKind::Memory; + ex->value = inner[1]->str(); } else if (elementStartsWith(inner, TABLE)) { ex->kind = ExternalKind::Table; + ex->value = getTableName(*inner[1]); } else if (elementStartsWith(inner, GLOBAL)) { ex->kind = ExternalKind::Global; + ex->value = getGlobalName(*inner[1]); } else if (inner[0]->str() == EVENT) { ex->kind = ExternalKind::Event; + ex->value = getEventName(*inner[1]); } else { throw ParseException("invalid export", inner.line, inner.col); } @@ -2505,10 +2527,6 @@ void SExpressionWasmBuilder::parseImport(Element& s) { wasm.memory.exists = true; } else if (elementStartsWith(*s[3], TABLE)) { kind = ExternalKind::Table; - if (wasm.table.exists) { - throw ParseException("more than one table", s[3]->line, s[3]->col); - } - wasm.table.exists = true; } else if (elementStartsWith(*s[3], GLOBAL)) { kind = ExternalKind::Global; } else if ((*s[3])[0]->str() == EVENT) { @@ -2590,21 +2608,27 @@ void SExpressionWasmBuilder::parseImport(Element& s) { global->mutable_ = mutable_; wasm.addGlobal(global.release()); } else if (kind == ExternalKind::Table) { - wasm.table.setName(name, hasExplicitName); - wasm.table.module = module; - wasm.table.base = base; + auto table = make_unique<Table>(); + table->setName(name, hasExplicitName); + table->module = module; + table->base = base; + tableNames.push_back(name); + if (j < inner.size() - 1) { auto initElem = inner[j++]; - wasm.table.initial = getAddress(initElem); - checkAddress(wasm.table.initial, "excessive table init size", initElem); + table->initial = getAddress(initElem); + checkAddress(table->initial, "excessive table init size", initElem); } if (j < inner.size() - 1) { auto maxElem = inner[j++]; - wasm.table.max = getAddress(maxElem); - checkAddress(wasm.table.max, "excessive table max size", maxElem); + table->max = getAddress(maxElem); + checkAddress(table->max, "excessive table max size", maxElem); } else { - wasm.table.max = Table::kUnlimitedSize; + table->max = Table::kUnlimitedSize; } + + wasm.addTable(std::move(table)); + j++; // funcref // ends with the table element type } else if (kind == ExternalKind::Memory) { @@ -2728,18 +2752,20 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { } void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { - if (wasm.table.exists) { - throw ParseException("more than one table", s.line, s.col); - } - wasm.table.exists = true; + std::unique_ptr<Table> table = make_unique<Table>(); Index i = 1; if (i == s.size()) { return; // empty table in old notation } if (s[i]->dollared()) { - wasm.table.setExplicitName(s[i++]->str()); + table->setExplicitName(s[i++]->str()); + } else { + table->name = Name::fromInt(tableCounter++); } + tableNames.push_back(table->name); + if (i == s.size()) { + wasm.addTable(std::move(table)); return; } Name importModule, importBase; @@ -2748,7 +2774,7 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { if (elementStartsWith(inner, EXPORT)) { auto ex = make_unique<Export>(); ex->name = inner[1]->str(); - ex->value = wasm.table.name; + ex->value = table->name; ex->kind = ExternalKind::Table; if (wasm.getExportOrNull(ex->name)) { throw ParseException("duplicate export", inner.line, inner.col); @@ -2759,26 +2785,27 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { if (!preParseImport) { throw ParseException("!preParseImport in table", inner.line, inner.col); } - wasm.table.module = inner[1]->str(); - wasm.table.base = inner[2]->str(); + table->module = inner[1]->str(); + table->base = inner[2]->str(); i++; } else { throw ParseException("invalid table", inner.line, inner.col); } } if (i == s.size()) { + wasm.addTable(std::move(table)); return; } if (!s[i]->dollared()) { if (s[i]->str() == FUNCREF) { // (table type (elem ..)) - parseInnerElem(*s[i + 1]); - if (wasm.table.segments.size() > 0) { - wasm.table.initial = wasm.table.max = - wasm.table.segments[0].data.size(); + parseInnerElem(table.get(), *s[i + 1]); + if (table->segments.size() > 0) { + table->initial = table->max = table->segments[0].data.size(); } else { - wasm.table.initial = wasm.table.max = 0; + table->initial = table->max = 0; } + wasm.addTable(std::move(table)); return; } // first element isn't dollared, and isn't funcref. this could be old syntax @@ -2787,39 +2814,87 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { if (s[s.size() - 1]->str() == FUNCREF) { // (table initial max? type) if (i < s.size() - 1) { - wasm.table.initial = atoi(s[i++]->c_str()); + table->initial = atoi(s[i++]->c_str()); } if (i < s.size() - 1) { - wasm.table.max = atoi(s[i++]->c_str()); + table->max = atoi(s[i++]->c_str()); } + wasm.addTable(std::move(table)); return; } } // old notation (table func1 func2 ..) - parseInnerElem(s, i); - if (wasm.table.segments.size() > 0) { - wasm.table.initial = wasm.table.max = wasm.table.segments[0].data.size(); + parseInnerElem(table.get(), s, i); + if (table->segments.size() > 0) { + table->initial = table->max = table->segments[0].data.size(); } else { - wasm.table.initial = wasm.table.max = 0; + table->initial = table->max = 0; } + + wasm.addTable(std::move(table)); } +// parses an elem segment +// elem ::= (elem (expr) vec(funcidx)) +// | (elem (offset (expr)) func vec(funcidx)) +// | (elem (table tableidx) (offset (expr)) func vec(funcidx)) +// +// abbreviation: +// (offset (expr)) ≡ (expr) +// (elem (expr) vec(funcidx)) ≡ (elem (table 0) (offset (expr)) func +// vec(funcidx)) +// void SExpressionWasmBuilder::parseElem(Element& s) { Index i = 1; + Table* table = nullptr; + Expression* offset = nullptr; + if (!s[i]->isList()) { - // the table is named - i++; + // optional segment id OR 'declare' OR start of elemList + i += 1; + } + + // old style refers to the pre-reftypes form of (elem (expr) vec(funcidx)) + bool oldStyle = true; + + while (1) { + auto& inner = *s[i++]; + if (elementStartsWith(inner, TABLE)) { + oldStyle = false; + Name tableName = getTableName(*inner[1]); + table = wasm.getTable(tableName); + } else { + if (elementStartsWith(inner, "offset")) { + offset = parseExpression(inner[1]); + } else { + offset = parseExpression(inner); + } + break; + } } - auto* offset = parseExpression(s[i++]); - parseInnerElem(s, i, offset); + + if (!oldStyle) { + if (strcmp(s[i]->c_str(), "func") != 0) { + throw ParseException( + "only the abbreviated form of elemList is supported."); + } + // ignore elemType for now + i += 1; + } + + if (wasm.tables.empty()) { + throw ParseException("elem without table", s.line, s.col); + } else if (!table) { + table = wasm.tables[0].get(); + } + + parseInnerElem(table, s, i, offset); } -void SExpressionWasmBuilder::parseInnerElem(Element& s, +void SExpressionWasmBuilder::parseInnerElem(Table* table, + Element& s, Index i, Expression* offset) { - if (!wasm.table.exists) { - throw ParseException("elem without table", s.line, s.col); - } if (!offset) { offset = allocator.alloc<Const>()->set(Literal(int32_t(0))); } @@ -2827,7 +2902,7 @@ void SExpressionWasmBuilder::parseInnerElem(Element& s, for (; i < s.size(); i++) { segment.data.push_back(getFunctionName(*s[i])); } - wasm.table.segments.push_back(segment); + table->segments.push_back(segment); } HeapType SExpressionWasmBuilder::parseHeapType(Element& s) { |