blob: 364f7ba324ac2efc345377992ef96937b5d19c5c [file] [log] [blame] [edit]
/*
* Copyright 2021 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "table-utils.h"
#include "element-utils.h"
#include "find_all.h"
#include "module-utils.h"
namespace wasm::TableUtils {
std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm) {
// Without reference types there are no ref.funcs or elem declare.
if (!wasm.features.hasReferenceTypes()) {
return {};
}
// Find all the names in the tables.
std::unordered_set<Name> tableNames;
ElementUtils::iterAllElementFunctionNames(
&wasm, [&](Name name) { tableNames.insert(name); });
// Find all the names in ref.funcs.
using Names = std::unordered_set<Name>;
ModuleUtils::ParallelFunctionAnalysis<Names> analysis(
wasm, [&](Function* func, Names& names) {
if (func->imported()) {
return;
}
for (auto* refFunc : FindAll<RefFunc>(func->body).list) {
names.insert(refFunc->func);
}
});
// Find the names that need to be declared.
std::set<Name> ret;
for (auto& kv : analysis.map) {
auto& names = kv.second;
for (auto name : names) {
if (!tableNames.count(name)) {
ret.insert(name);
}
}
}
return ret;
}
bool usesExpressions(ElementSegment* curr, Module* module) {
// Binaryen IR always has ref.funcs for functions in tables for uniformity,
// so that by itself does not indicate if expressions should be used when
// emitting the table or not. But definitely anything that is not a ref.func
// implies we are post-MVP and must use expressions.
bool allElementsRefFunc =
std::all_of(curr->data.begin(), curr->data.end(), [](Expression* entry) {
return entry->is<RefFunc>();
});
// If the segment has a specialized (non-MVP) type, then it must use the
// post-MVP form of using expressions.
bool hasSpecializedType = curr->type != Type(HeapType::func, Nullable);
return !allElementsRefFunc || hasSpecializedType;
}
TableInfoMap computeTableInfo(Module& wasm, bool initialContentsImmutable) {
// Set up the initial info.
TableInfoMap tables;
if (wasm.tables.empty()) {
return tables;
}
for (auto& table : wasm.tables) {
tables[table->name].initialContentsImmutable = initialContentsImmutable;
tables[table->name].flatTable =
std::make_unique<TableUtils::FlatTable>(wasm, *table);
}
// Next, look at the imports and exports.
for (auto& table : wasm.tables) {
if (table->imported()) {
tables[table->name].mayBeModified = true;
}
}
for (auto& ex : wasm.exports) {
if (ex->kind == ExternalKind::Table) {
tables[*ex->getInternalName()].mayBeModified = true;
}
}
// Find which tables have sets, by scanning for instructions. Only do so if we
// might learn anything new.
auto hasUnmodifiableTable = false;
for (auto& [_, info] : tables) {
if (!info.mayBeModified) {
hasUnmodifiableTable = true;
break;
}
}
if (!hasUnmodifiableTable) {
return tables;
}
using TablesWithSet = std::unordered_set<Name>;
ModuleUtils::ParallelFunctionAnalysis<TablesWithSet> analysis(
wasm, [&](Function* func, TablesWithSet& tablesWithSet) {
if (func->imported()) {
return;
}
struct Finder : public PostWalker<Finder> {
TablesWithSet& tablesWithSet;
Finder(TablesWithSet& tablesWithSet) : tablesWithSet(tablesWithSet) {}
void visitTableSet(TableSet* curr) {
tablesWithSet.insert(curr->table);
}
void visitTableFill(TableFill* curr) {
tablesWithSet.insert(curr->table);
}
void visitTableCopy(TableCopy* curr) {
tablesWithSet.insert(curr->destTable);
}
void visitTableInit(TableInit* curr) {
tablesWithSet.insert(curr->table);
}
};
Finder(tablesWithSet).walkFunction(func);
});
for (auto& [_, names] : analysis.map) {
for (auto name : names) {
tables[name].mayBeModified = true;
}
}
return tables;
}
} // namespace wasm::TableUtils