[Wasm] Improve interface method dispatch

- Use typed Wasm tables for each interface method to avoid runtime
  function type check

- Use linear search by implemented interface rather than by individual
  virtual function signature
This commit is contained in:
Svyatoslav Kuzmich
2020-12-13 20:55:40 +03:00
parent e7dc199ad7
commit b6ad1584c9
33 changed files with 318 additions and 172 deletions
@@ -76,7 +76,7 @@ class WasmData(
) : WasmNamedModuleField()
class WasmTable(
val limits: WasmLimits = WasmLimits(1u, null),
var limits: WasmLimits = WasmLimits(1u, null),
val elementType: WasmType,
val importPair: WasmImportPair? = null
) : WasmNamedModuleField() {
@@ -73,7 +73,9 @@ sealed class WasmImmediate {
}
class DataIdx(val value: Int) : WasmImmediate()
class TableIdx(val value: Int) : WasmImmediate()
class TableIdx(val value: WasmSymbolReadOnly<Int>) : WasmImmediate() {
constructor(value: Int) : this(WasmSymbol(value))
}
class LabelIdx(val value: Int) : WasmImmediate()
class LabelIdxVector(val value: List<Int>) : WasmImmediate()
@@ -33,3 +33,10 @@ class WasmSymbol<out T : Any>(owner: T? = null) : WasmSymbolReadOnly<T> {
override fun toString(): String =
_owner?.toString() ?: "UNBOUND-WASM-SYMBOL"
}
class WasmSymbolIntWrapper(val symbol: WasmSymbol<WasmNamedModuleField>) : WasmSymbolReadOnly<Int> {
override val owner: Int
get() = symbol.owner.id!!
override fun toString() = owner.toString()
}
@@ -82,11 +82,14 @@ abstract class WasmExpressionBuilder {
buildInstr(WasmOp.CALL, WasmImmediate.FuncIdx(symbol))
}
fun buildCallIndirect(symbol: WasmSymbol<WasmFunctionType>) {
fun buildCallIndirect(
symbol: WasmSymbol<WasmFunctionType>,
tableIdx: WasmSymbolReadOnly<Int> = WasmSymbol(0),
) {
buildInstr(
WasmOp.CALL_INDIRECT,
WasmImmediate.TypeIdx(symbol),
WasmImmediate.TableIdx(0)
WasmImmediate.TableIdx(tableIdx)
)
}
@@ -23,3 +23,9 @@ class WasmIrExpressionBuilder(
override val lastInstr: WasmOp?
get() = expression.lastOrNull()?.operator
}
inline fun buildWasmExpression(body: WasmExpressionBuilder.() -> Unit): MutableList<WasmInstr> {
val res = mutableListOf<WasmInstr>()
WasmIrExpressionBuilder(res).body()
return res
}
@@ -138,7 +138,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) {
is WasmImmediate.TypeIdx -> appendModuleFieldReference(x.value.owner)
is WasmImmediate.MemoryIdx -> appendModuleFieldReference(x.value.owner)
is WasmImmediate.DataIdx -> b.writeVarUInt32(x.value)
is WasmImmediate.TableIdx -> b.writeVarUInt32(x.value)
is WasmImmediate.TableIdx -> b.writeVarUInt32(x.value.owner)
is WasmImmediate.LabelIdx -> b.writeVarUInt32(x.value)
is WasmImmediate.LabelIdxVector -> {
b.writeVarUInt32(x.value.size)
@@ -243,7 +243,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) {
b.writeByte(1)
}
b.writeVarInt7(table.elementType.code)
appendType(table.elementType)
appendLimits(table.limits)
}
@@ -286,7 +286,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) {
}
private fun appendElement(element: WasmElement) {
val isFuncIndices = element.values.all { it is WasmTable.Value.Function }
val isFuncIndices = element.values.all { it is WasmTable.Value.Function } && element.type == WasmFuncRef
val funcIndices = if (isFuncIndices) {
element.values.map { (it as WasmTable.Value.Function).function.owner.id!! }