diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 225 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 1 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 132 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 30 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 34 |
5 files changed, 271 insertions, 151 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 0f40cfd58..dacb6edbb 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -55,7 +55,7 @@ void WasmBinaryWriter::write() { writeGlobals(); writeExports(); writeStart(); - writeTableElements(); + writeElementSegments(); writeDataCount(); writeFunctions(); writeDataSegments(); @@ -552,11 +552,8 @@ void WasmBinaryWriter::writeTableDeclarations() { finishSection(start); } -void WasmBinaryWriter::writeTableElements() { - size_t elemCount = 0; - for (auto& table : wasm->tables) { - elemCount += table->segments.size(); - } +void WasmBinaryWriter::writeElementSegments() { + size_t elemCount = wasm->elementSegments.size(); auto needingElemDecl = TableUtils::getFunctionsNeedingElemDeclare(*wasm); if (!needingElemDecl.empty()) { elemCount++; @@ -565,40 +562,50 @@ void WasmBinaryWriter::writeTableElements() { return; } - BYN_TRACE("== writeTableElements\n"); + BYN_TRACE("== writeElementSegments\n"); auto start = startSection(BinaryConsts::Section::Element); o << U32LEB(elemCount); - for (auto& table : wasm->tables) { - for (auto& segment : table->segments) { - Index tableIdx = getTableIndex(table->name); - // No support for passive element segments yet as they don't belong to a - // table. - bool isPassive = false; - bool isDeclarative = false; - bool hasTableIndex = tableIdx > 0; - bool usesExpressions = false; - - uint32_t flags = - (isPassive ? BinaryConsts::IsPassive | - (isDeclarative ? BinaryConsts::IsDeclarative : 0) - : (hasTableIndex ? BinaryConsts::HasIndex : 0)) | - (usesExpressions ? BinaryConsts::UsesExpressions : 0); - - o << U32LEB(flags); + for (auto& segment : wasm->elementSegments) { + Index tableIdx = 0; + + bool isPassive = segment->table.isNull(); + // TODO(reference-types): add support for writing expressions instead of + // function indices. + bool usesExpressions = false; + + bool hasTableIndex = false; + if (!isPassive) { + tableIdx = getTableIndex(segment->table); + hasTableIndex = tableIdx > 0; + } + + uint32_t flags = 0; + if (usesExpressions) { + flags |= BinaryConsts::UsesExpressions; + } + if (isPassive) { + flags |= BinaryConsts::IsPassive; + } else if (hasTableIndex) { + flags |= BinaryConsts::HasIndex; + } + + o << U32LEB(flags); + if (!isPassive) { if (hasTableIndex) { o << U32LEB(tableIdx); } - writeExpression(segment.offset); + writeExpression(segment->offset); o << int8_t(BinaryConsts::End); - if (!usesExpressions && (isPassive || hasTableIndex)) { - // elemKind funcref - o << U32LEB(0); - } - o << U32LEB(segment.data.size()); - for (auto name : segment.data) { - o << U32LEB(getFunctionIndex(name)); - } + } + + if (!usesExpressions && (isPassive || hasTableIndex)) { + // elemKind funcref + o << U32LEB(0); + } + o << U32LEB(segment->data.size()); + for (auto& name : segment->data) { + o << U32LEB(getFunctionIndex(name)); } } @@ -765,6 +772,32 @@ void WasmBinaryWriter::writeNames() { } } + // elem names + { + std::vector<std::pair<Index, ElementSegment*>> elemsWithNames; + Index checked = 0; + for (auto& curr : wasm->elementSegments) { + if (curr->hasExplicitName) { + elemsWithNames.push_back({checked, curr.get()}); + } + checked++; + } + assert(checked == indexes.elemIndexes.size()); + + if (elemsWithNames.size() > 0) { + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameElem); + o << U32LEB(elemsWithNames.size()); + + for (auto& indexedElem : elemsWithNames) { + o << U32LEB(indexedElem.first); + writeEscapedName(indexedElem.second->name.str); + } + + finishSubsection(substart); + } + } + // memory names if (wasm->memory.exists && wasm->memory.hasExplicitName) { auto substart = @@ -1337,7 +1370,7 @@ void WasmBinaryBuilder::read() { readExports(); break; case BinaryConsts::Section::Element: - readTableElements(); + readElementSegments(); break; case BinaryConsts::Section::Global: readGlobals(); @@ -1349,7 +1382,7 @@ void WasmBinaryBuilder::read() { readDataCount(); break; case BinaryConsts::Section::Table: - readFunctionTableDeclaration(); + readTableDeclarations(); break; case BinaryConsts::Section::Event: readEvents(); @@ -2549,6 +2582,9 @@ void WasmBinaryBuilder::processNames() { for (auto& table : tables) { wasm.addTable(std::move(table)); } + for (auto& segment : elementSegments) { + wasm.addElementSegment(std::move(segment)); + } // now that we have names, apply things @@ -2607,14 +2643,11 @@ void WasmBinaryBuilder::processNames() { } } - for (auto& table_pair : functionTable) { - for (auto& pair : table_pair.second) { - auto i = pair.first; - auto& indices = pair.second; - for (auto j : indices) { - wasm.tables[table_pair.first]->segments[i].data.push_back( - getFunctionName(j)); - } + for (auto& pair : functionTable) { + auto i = pair.first; + auto& indices = pair.second; + for (auto j : indices) { + wasm.elementSegments[i]->data.push_back(getFunctionName(j)); } } @@ -2670,8 +2703,8 @@ void WasmBinaryBuilder::readDataSegments() { } } -void WasmBinaryBuilder::readFunctionTableDeclaration() { - BYN_TRACE("== readFunctionTableDeclaration\n"); +void WasmBinaryBuilder::readTableDeclarations() { + BYN_TRACE("== readTableDeclarations\n"); auto numTables = getU32LEB(); for (size_t i = 0; i < numTables; i++) { @@ -2695,8 +2728,8 @@ void WasmBinaryBuilder::readFunctionTableDeclaration() { } } -void WasmBinaryBuilder::readTableElements() { - BYN_TRACE("== readTableElements\n"); +void WasmBinaryBuilder::readElementSegments() { + BYN_TRACE("== readElementSegments\n"); auto numSegments = getU32LEB(); if (numSegments >= Table::kMaxSize) { throwError("Too many segments"); @@ -2704,55 +2737,63 @@ void WasmBinaryBuilder::readTableElements() { for (size_t i = 0; i < numSegments; i++) { auto flags = getU32LEB(); bool isPassive = (flags & BinaryConsts::IsPassive) != 0; - bool hasTableIdx = (flags & BinaryConsts::HasIndex) != 0; + bool hasTableIdx = !isPassive && ((flags & BinaryConsts::HasIndex) != 0); + bool isDeclarative = + isPassive && ((flags & BinaryConsts::IsDeclarative) != 0); bool usesExpressions = (flags & BinaryConsts::UsesExpressions) != 0; - if (isPassive) { - bool isDeclarative = (flags & BinaryConsts::IsDeclarative) != 0; - if (isDeclarative) { - // "elem declare" is needed in wasm text and binary, but not in Binaryen - // IR; read and ignore the contents. - auto type = getU32LEB(); - WASM_UNUSED(type); - auto num = getU32LEB(); - for (Index i = 0; i < num; i++) { - getU32LEB(); - } - continue; + if (isDeclarative) { + // Declared segments are needed in wasm text and binary, but not in + // Binaryen IR; skip over the segment + auto type = getU32LEB(); + WASM_UNUSED(type); + auto num = getU32LEB(); + for (Index i = 0; i < num; i++) { + getU32LEB(); } - - throwError("Only active elem segments are supported."); + continue; } if (usesExpressions) { throwError("Only elem segments with function indexes are supported."); } - Index tableIdx = 0; - if (hasTableIdx) { - tableIdx = getU32LEB(); - } + if (!isPassive) { + Index tableIdx = 0; + if (hasTableIdx) { + tableIdx = getU32LEB(); + } - auto numTableImports = tableImports.size(); - if (tableIdx < numTableImports) { - auto table = tableImports[tableIdx]; - table->segments.emplace_back(readExpression()); - } else if (tableIdx - numTableImports < tables.size()) { - auto table = tables[tableIdx - numTableImports].get(); - table->segments.emplace_back(readExpression()); + auto makeActiveElem = [&](Table* table) { + auto segment = + std::make_unique<ElementSegment>(table->name, readExpression()); + segment->setName(Name::fromInt(i), false); + elementSegments.push_back(std::move(segment)); + }; + + auto numTableImports = tableImports.size(); + if (tableIdx < numTableImports) { + makeActiveElem(tableImports[tableIdx]); + } else if (tableIdx - numTableImports < tables.size()) { + makeActiveElem(tables[tableIdx - numTableImports].get()); + } else { + throwError("Table index out of range."); + } } else { - throwError("Table index out of range."); + auto segment = std::make_unique<ElementSegment>(); + segment->setName(Name::fromInt(i), false); + elementSegments.push_back(std::move(segment)); } - if (hasTableIdx) { + if (isPassive || hasTableIdx) { auto elemKind = getU32LEB(); if (elemKind != 0x0) { throwError("Only funcref elem kinds are valid."); } } - size_t segmentIndex = functionTable[tableIdx].size(); - auto& indexSegment = functionTable[tableIdx][segmentIndex]; + size_t segmentIndex = functionTable.size(); + auto& indexSegment = functionTable[segmentIndex]; auto size = getU32LEB(); for (Index j = 0; j < size; j++) { indexSegment.push_back(getU32LEB()); @@ -2921,10 +2962,19 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { auto rawName = getInlineString(); auto name = processor.process(rawName); auto numTableImports = tableImports.size(); + auto setTableName = [&](Table* table) { + for (auto& segment : elementSegments) { + if (segment->table == table->name) { + segment->table = name; + } + } + table->setExplicitName(name); + }; + if (index < numTableImports) { - tableImports[index]->setExplicitName(name); + setTableName(tableImports[index]); } else if (index - numTableImports < tables.size()) { - tables[index - numTableImports]->setExplicitName(name); + setTableName(tables[index - numTableImports].get()); } else { std::cerr << "warning: table index out of bounds in name section, " "table subsection: " @@ -2932,6 +2982,23 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { << std::to_string(index) << std::endl; } } + } else if (nameType == BinaryConsts::UserSections::Subsection::NameElem) { + auto num = getU32LEB(); + NameProcessor processor; + for (size_t i = 0; i < num; i++) { + auto index = getU32LEB(); + auto rawName = getInlineString(); + auto name = processor.process(rawName); + + if (index < elementSegments.size()) { + elementSegments[index]->setExplicitName(name); + } else { + std::cerr << "warning: elem index out of bounds in name section, " + "elem subsection: " + << std::string(rawName.str) << " at index " + << std::to_string(index) << std::endl; + } + } } else if (nameType == BinaryConsts::UserSections::Subsection::NameMemory) { auto num = getU32LEB(); for (size_t i = 0; i < num; i++) { diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 339214f43..d97121544 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -23,7 +23,6 @@ #include "ir/import-utils.h" #include "ir/literal-utils.h" #include "ir/module-utils.h" -#include "ir/table-utils.h" #include "shared-constants.h" #include "support/debug.h" #include "wasm-builder.h" diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 31ae188d0..91ed5056f 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -51,7 +51,7 @@ int unhex(char c) { namespace wasm { static Name STRUCT("struct"), FIELD("field"), ARRAY("array"), I8("i8"), - I16("i16"), RTT("rtt"), DECLARE("declare"); + I16("i16"), RTT("rtt"), DECLARE("declare"), ITEM("item"), OFFSET("offset"); static Address getAddress(const Element* s) { return atoll(s->c_str()); } @@ -3215,15 +3215,25 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { wasm.addTable(std::move(table)); return; } + + auto parseTableElem = [&](Table* table, Element& s) { + parseElem(s, table); + auto it = std::find_if(wasm.elementSegments.begin(), + wasm.elementSegments.end(), + [&](std::unique_ptr<ElementSegment>& segment) { + return segment->table == table->name; + }); + if (it != wasm.elementSegments.end()) { + table->initial = table->max = it->get()->data.size(); + } else { + table->initial = table->max = 0; + } + }; + if (!s[i]->dollared()) { if (s[i]->str() == FUNCREF) { // (table type (elem ..)) - parseInnerElem(table.get(), *s[i + 1]); - if (table->segments.size() > 0) { - table->initial = table->max = table->segments[0].data.size(); - } else { - table->initial = table->max = 0; - } + parseTableElem(table.get(), *s[i + 1]); wasm.addTable(std::move(table)); return; } @@ -3243,13 +3253,7 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { } } // old notation (table func1 func2 ..) - parseInnerElem(table.get(), s, i); - if (table->segments.size() > 0) { - table->initial = table->max = table->segments[0].data.size(); - } else { - table->initial = table->max = 0; - } - + parseTableElem(table.get(), s); wasm.addTable(std::move(table)); } @@ -3257,49 +3261,77 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { // elem ::= (elem (expr) vec(funcidx)) // | (elem (offset (expr)) func vec(funcidx)) // | (elem (table tableidx) (offset (expr)) func vec(funcidx)) -// | (elem declare func $foo) +// | (elem func vec(funcidx)) +// | (elem declare func vec(funcidx)) // // abbreviation: // (offset (expr)) ≡ (expr) // (elem (expr) vec(funcidx)) ≡ (elem (table 0) (offset (expr)) func // vec(funcidx)) // -void SExpressionWasmBuilder::parseElem(Element& s) { +void SExpressionWasmBuilder::parseElem(Element& s, Table* table) { Index i = 1; - Table* table = nullptr; - Expression* offset = nullptr; + Name name = Name::fromInt(elemCounter++); + bool hasExplicitName = false; + + if (table) { + Expression* offset = allocator.alloc<Const>()->set(Literal(int32_t(0))); + auto segment = std::make_unique<ElementSegment>(table->name, offset); + segment->setName(name, hasExplicitName); + parseElemFinish(s, segment, i); + return; + } - if (!s[i]->isList()) { - // optional segment id OR 'declare' OR start of elemList - if (s[i]->str() == DECLARE) { - // "elem declare" is needed in wasm text and binary, but not in Binaryen - // IR; ignore the contents. - return; - } - i += 1; + if (s[i]->isStr() && s[i]->dollared()) { + name = s[i++]->str(); + hasExplicitName = true; + } + if (s[i]->isStr() && s[i]->str() == DECLARE) { + // We don't store declared segments in the IR + return; } - // old style refers to the pre-reftypes form of (elem (expr) vec(funcidx)) + if (s[i]->isStr() && s[i]->str() == FUNC) { + auto segment = std::make_unique<ElementSegment>(); + segment->setName(name, hasExplicitName); + parseElemFinish(s, segment, i + 1); + return; + } + + // old style refers to the pre-reftypes form of (elem 0? (expr) vec(funcidx)) bool oldStyle = true; - while (1) { + // At this point, we know that we're parsing an active element segment. A + // table will be mandatory now. + if (wasm.tables.empty()) { + throw ParseException("elem without table", s.line, s.col); + } + + // Old style table index (elem 0 (i32.const 0) ...) + if (s[i]->isStr()) { + i += 1; + } + + if (s[i]->isList() && elementStartsWith(s[i], TABLE)) { + oldStyle = false; auto& inner = *s[i++]; - if (elementStartsWith(inner, TABLE)) { + Name tableName = getTableName(*inner[1]); + table = wasm.getTable(tableName); + } + + Expression* offset = nullptr; + if (s[i]->isList()) { + auto& inner = *s[i++]; + if (elementStartsWith(inner, OFFSET)) { + offset = parseExpression(inner[1]); 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; + offset = parseExpression(inner); } } if (!oldStyle) { - if (strcmp(s[i]->c_str(), "func") != 0) { + if (s[i]->str() != FUNC) { throw ParseException( "only the abbreviated form of elemList is supported."); } @@ -3307,27 +3339,21 @@ void SExpressionWasmBuilder::parseElem(Element& s) { i += 1; } - if (wasm.tables.empty()) { - throw ParseException("elem without table", s.line, s.col); - } else if (!table) { - table = wasm.tables[0].get(); + if (!table) { + table = wasm.tables.front().get(); } - parseInnerElem(table, s, i, offset); + auto segment = std::make_unique<ElementSegment>(table->name, offset); + segment->setName(name, hasExplicitName); + parseElemFinish(s, segment, i); } -void SExpressionWasmBuilder::parseInnerElem(Table* table, - Element& s, - Index i, - Expression* offset) { - if (!offset) { - offset = allocator.alloc<Const>()->set(Literal(int32_t(0))); - } - Table::Segment segment(offset); +ElementSegment* SExpressionWasmBuilder::parseElemFinish( + Element& s, std::unique_ptr<ElementSegment>& segment, Index i) { for (; i < s.size(); i++) { - segment.data.push_back(getFunctionName(*s[i])); + segment->data.push_back(getFunctionName(*s[i])); } - table->segments.push_back(segment); + return wasm.addElementSegment(std::move(segment)); } HeapType SExpressionWasmBuilder::parseHeapType(Element& s) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index e95950bb5..656c5e832 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2882,21 +2882,25 @@ static void validateTables(Module& module, ValidationInfo& info) { "Only 1 table definition allowed in MVP (requires " "--enable-reference-types)"); } - for (auto& curr : module.tables) { - for (auto& segment : curr->segments) { - info.shouldBeEqual(segment.offset->type, + + for (auto& segment : module.elementSegments) { + if (segment->table.is()) { + auto table = module.getTableOrNull(segment->table); + info.shouldBeTrue( + table != nullptr, "elem", "elem segment must have a valid table name"); + info.shouldBeEqual(segment->offset->type, Type(Type::i32), - segment.offset, - "segment offset should be i32"); - info.shouldBeTrue(checkSegmentOffset(segment.offset, - segment.data.size(), - curr->initial * Table::kPageSize), - segment.offset, + segment->offset, + "elem segment offset should be i32"); + info.shouldBeTrue(checkSegmentOffset(segment->offset, + segment->data.size(), + table->initial * Table::kPageSize), + segment->offset, "table segment offset should be reasonable"); - for (auto name : segment.data) { - info.shouldBeTrue( - module.getFunctionOrNull(name), name, "segment name should be valid"); - } + } + for (auto name : segment->data) { + info.shouldBeTrue( + module.getFunctionOrNull(name), name, "segment name should be valid"); } } } diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 92e03f579..ef8cfb2f7 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -70,6 +70,9 @@ Name EXPORT("export"); Name IMPORT("import"); Name TABLE("table"); Name ELEM("elem"); +Name DECLARE("declare"); +Name OFFSET("offset"); +Name ITEM("item"); Name LOCAL("local"); Name TYPE("type"); Name REF("ref"); @@ -802,12 +805,9 @@ void MemoryGrow::finalize() { void RefNull::finalize(HeapType heapType) { type = Type(heapType, Nullable); } -void RefNull::finalize(Type type_) { - type = type_; -} +void RefNull::finalize(Type type_) { type = type_; } -void RefNull::finalize() { -} +void RefNull::finalize() {} void RefIs::finalize() { if (value->type == Type::unreachable) { @@ -1169,6 +1169,10 @@ Table* Module::getTable(Name name) { return getModuleElement(tablesMap, name, "getTable"); } +ElementSegment* Module::getElementSegment(Name name) { + return getModuleElement(elementSegmentsMap, name, "getElementSegment"); +} + Global* Module::getGlobal(Name name) { return getModuleElement(globalsMap, name, "getGlobal"); } @@ -1198,6 +1202,10 @@ Table* Module::getTableOrNull(Name name) { return getModuleElementOrNull(tablesMap, name); } +ElementSegment* Module::getElementSegmentOrNull(Name name) { + return getModuleElementOrNull(elementSegmentsMap, name); +} + Global* Module::getGlobalOrNull(Name name) { return getModuleElementOrNull(globalsMap, name); } @@ -1267,6 +1275,12 @@ Table* Module::addTable(std::unique_ptr<Table>&& curr) { return addModuleElement(tables, tablesMap, std::move(curr), "addTable"); } +ElementSegment* +Module::addElementSegment(std::unique_ptr<ElementSegment>&& curr) { + return addModuleElement( + elementSegments, elementSegmentsMap, std::move(curr), "addElementSegment"); +} + Global* Module::addGlobal(std::unique_ptr<Global>&& curr) { return addModuleElement(globals, globalsMap, std::move(curr), "addGlobal"); } @@ -1297,6 +1311,9 @@ void Module::removeFunction(Name name) { void Module::removeTable(Name name) { removeModuleElement(tables, tablesMap, name); } +void Module::removeElementSegment(Name name) { + removeModuleElement(elementSegments, elementSegmentsMap, name); +} void Module::removeGlobal(Name name) { removeModuleElement(globals, globalsMap, name); } @@ -1329,6 +1346,9 @@ void Module::removeFunctions(std::function<bool(Function*)> pred) { void Module::removeTables(std::function<bool(Table*)> pred) { removeModuleElements(tables, tablesMap, pred); } +void Module::removeElementSegments(std::function<bool(ElementSegment*)> pred) { + removeModuleElements(elementSegments, elementSegmentsMap, pred); +} void Module::removeGlobals(std::function<bool(Global*)> pred) { removeModuleElements(globals, globalsMap, pred); } @@ -1349,6 +1369,10 @@ void Module::updateMaps() { for (auto& curr : tables) { tablesMap[curr->name] = curr.get(); } + elementSegmentsMap.clear(); + for (auto& curr : elementSegments) { + elementSegmentsMap[curr->name] = curr.get(); + } globalsMap.clear(); for (auto& curr : globals) { globalsMap[curr->name] = curr.get(); |