7deaf2053d
Specifically for the dispatch table, a single function can map to multiple indicies so the function -> index map is not injective and we end up overwriting entries. Change-Id: I6ca69d5220b539328bafd215d45c52dac9d2e72e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385181 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Nate Biggs <natebiggs@google.com>
91 lines
2.9 KiB
Dart
91 lines
2.9 KiB
Dart
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'dart:collection';
|
|
|
|
import 'package:wasm_builder/wasm_builder.dart' as w;
|
|
|
|
import 'translator.dart';
|
|
|
|
class StaticDispatchTables {
|
|
final Translator translator;
|
|
|
|
final Map<w.FunctionType, StaticDispatchTableForSignature> _tables =
|
|
LinkedHashMap(
|
|
hashCode: (t) =>
|
|
Object.hash(Object.hashAll(t.inputs), Object.hashAll(t.outputs)),
|
|
equals: (t1, t2) => t1.isStructurallyEqualTo(t2));
|
|
|
|
StaticDispatchTables(this.translator);
|
|
|
|
StaticDispatchTableForSignature getTableForType(w.FunctionType type) {
|
|
return _tables[type] ??=
|
|
StaticDispatchTableForSignature(translator, type, _tables.length);
|
|
}
|
|
|
|
void outputTables() {
|
|
for (final table in _tables.values) {
|
|
table.output();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Builds a static dispatch table for a specific function type signature.
|
|
///
|
|
/// All calls to this table will have the same signature and so `call_indirect`
|
|
/// instructions that reference this table can omit the type check.
|
|
class StaticDispatchTableForSignature {
|
|
final w.FunctionType _functionType;
|
|
|
|
final Translator translator;
|
|
|
|
/// Contents of wasm table.
|
|
final Map<w.BaseFunction, int> _table = {};
|
|
|
|
late final w.TableBuilder _definedWasmTable;
|
|
final WasmTableImporter _importedWasmTables;
|
|
|
|
StaticDispatchTableForSignature(
|
|
this.translator, this._functionType, int nameCounter)
|
|
: _importedWasmTables =
|
|
WasmTableImporter(translator, 'static$nameCounter-') {
|
|
_definedWasmTable = translator.mainModule.tables
|
|
.define(w.RefType(_functionType, nullable: true), _table.length);
|
|
}
|
|
|
|
/// Gets the wasm table used to reference this static dispatch table in
|
|
/// [module].
|
|
///
|
|
/// This can either be the table definition itself or an import of it. Imports
|
|
/// the table into [module] if it is not imported yet.
|
|
w.Table getWasmTable(w.ModuleBuilder module) {
|
|
return _importedWasmTables.get(_definedWasmTable, module);
|
|
}
|
|
|
|
/// Returns the index for [function] in the table allocating one if necessary.
|
|
int indexForFunction(w.BaseFunction function) {
|
|
assert(function.type.isStructurallyEqualTo(function.type));
|
|
return _table[function] ??= _table.length;
|
|
}
|
|
|
|
void output() {
|
|
final importedTables = _importedWasmTables;
|
|
_table.forEach((fun, index) {
|
|
final targetModule = fun.enclosingModule;
|
|
if (translator.isMainModule(targetModule)) {
|
|
_definedWasmTable.setElement(index, fun);
|
|
} else {
|
|
// This will generate the imported table if it doesn't already exist.
|
|
(getWasmTable(targetModule) as w.ImportedTable).setElements[index] =
|
|
fun;
|
|
}
|
|
});
|
|
|
|
_definedWasmTable.minSize = _table.length;
|
|
for (final table in importedTables.imports) {
|
|
table.minSize = _table.length;
|
|
}
|
|
}
|
|
}
|