[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
@@ -9,9 +9,11 @@ package kotlin.wasm.internal
internal const val TYPE_INFO_ELEMENT_SIZE = 4
internal const val TYPE_INFO_VTABLE_OFFSET = 2 * TYPE_INFO_ELEMENT_SIZE
internal const val TYPE_INFO_VTABLE_LENGTH_OFFSET = TYPE_INFO_ELEMENT_SIZE
internal const val SUPER_CLASS_ID_OFFSET = 0
internal const val TYPE_INFO_ITABLE_PTR_OFFSET = SUPER_CLASS_ID_OFFSET + TYPE_INFO_ELEMENT_SIZE
internal const val TYPE_INFO_VTABLE_LENGTH_OFFSET = TYPE_INFO_ITABLE_PTR_OFFSET + TYPE_INFO_ELEMENT_SIZE
internal const val TYPE_INFO_VTABLE_OFFSET = TYPE_INFO_VTABLE_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE
internal fun getVtablePtr(obj: Any): Int =
obj.typeInfo + TYPE_INFO_VTABLE_OFFSET
@@ -19,8 +21,11 @@ internal fun getVtablePtr(obj: Any): Int =
internal fun getVtableLength(obj: Any): Int =
wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET)
internal fun getInterfaceListLength(obj: Any): Int =
wasm_i32_load(obj.typeInfo + TYPE_INFO_VTABLE_LENGTH_OFFSET)
internal fun getItablePtr(obj: Any): Int =
wasm_i32_load(obj.typeInfo + TYPE_INFO_ITABLE_PTR_OFFSET)
internal fun getInterfaceListLength(itablePtr: Int): Int =
wasm_i32_load(itablePtr + TYPE_INFO_VTABLE_LENGTH_OFFSET)
internal fun getSuperClassId(obj: Any): Int =
wasm_i32_load(obj.typeInfo + SUPER_CLASS_ID_OFFSET)
@@ -31,17 +36,22 @@ internal fun getVirtualMethodId(obj: Any, virtualFunctionSlot: Int): Int {
return wasm_i32_load(methodIdPtr)
}
internal fun getInterfaceMethodId(obj: Any, methodSignatureId: Int): Int {
val vtableLength = getVtableLength(obj)
val vtableSignatures = getVtablePtr(obj) + vtableLength * TYPE_INFO_ELEMENT_SIZE
var virtualFunctionSlot = 0
while (virtualFunctionSlot < vtableLength) {
if (wasm_i32_load(vtableSignatures + virtualFunctionSlot * TYPE_INFO_ELEMENT_SIZE) == methodSignatureId) {
return getVirtualMethodId(obj, virtualFunctionSlot)
// Returns -1 if obj does not implement interface
internal fun getInterfaceImplId(obj: Any, interfaceId: Int): Int {
val interfaceListSizePtr = getItablePtr(obj)
val interfaceListPtr = interfaceListSizePtr + TYPE_INFO_ELEMENT_SIZE
val interfaceListSize = wasm_i32_load(interfaceListSizePtr)
var interfaceSlot = 0
while (interfaceSlot < interfaceListSize) {
val supportedInterface = wasm_i32_load(interfaceListPtr + interfaceSlot * TYPE_INFO_ELEMENT_SIZE)
if (supportedInterface == interfaceId) {
return wasm_i32_load(interfaceListPtr + interfaceListSize * TYPE_INFO_ELEMENT_SIZE + interfaceSlot * TYPE_INFO_ELEMENT_SIZE)
}
virtualFunctionSlot++
interfaceSlot++
}
wasm_unreachable()
return -1
}
@@ -57,21 +67,7 @@ internal fun isSubClass(obj: Any, classId: Int): Boolean {
}
internal fun isInterface(obj: Any, interfaceId: Int): Boolean {
val vtableLength = getVtableLength(obj)
val interfaceListSizePtr = getVtablePtr(obj) + 2 * vtableLength * TYPE_INFO_ELEMENT_SIZE
val interfaceListPtr = interfaceListSizePtr + TYPE_INFO_ELEMENT_SIZE
val interfaceListSize = wasm_i32_load(interfaceListSizePtr)
var interfaceSlot = 0
while (interfaceSlot < interfaceListSize) {
val supportedInterface = wasm_i32_load(interfaceListPtr + interfaceSlot * TYPE_INFO_ELEMENT_SIZE)
if (supportedInterface == interfaceId) {
return true
}
interfaceSlot++
}
return false
return getInterfaceImplId(obj, interfaceId) != -1
}
@ExcludedFromCodegen