[WASM] Refcast and Reftest refactorings
This commit is contained in:
@@ -154,9 +154,9 @@ class WasmSymbols(
|
|||||||
val refEq = getInternalFunction("wasm_ref_eq")
|
val refEq = getInternalFunction("wasm_ref_eq")
|
||||||
val refIsNull = getInternalFunction("wasm_ref_is_null")
|
val refIsNull = getInternalFunction("wasm_ref_is_null")
|
||||||
val refTest = getInternalFunction("wasm_ref_test")
|
val refTest = getInternalFunction("wasm_ref_test")
|
||||||
val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
|
val refCast = getInternalFunction("wasm_ref_cast")
|
||||||
|
|
||||||
val wasmRefCast = getInternalFunction("wasm_ref_cast")
|
val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
|
||||||
|
|
||||||
val rangeCheck = getInternalFunction("rangeCheck")
|
val rangeCheck = getInternalFunction("rangeCheck")
|
||||||
val assertFuncs = findFunctions(kotlinTopLevelPackage.memberScope, Name.identifier("assert")).map { symbolTable.referenceSimpleFunction(it) }
|
val assertFuncs = findFunctions(kotlinTopLevelPackage.memberScope, Name.identifier("assert")).map { symbolTable.referenceSimpleFunction(it) }
|
||||||
@@ -250,6 +250,8 @@ class WasmSymbols(
|
|||||||
private val wasmDataRefClass = getIrClass(FqName("kotlin.wasm.internal.reftypes.dataref"))
|
private val wasmDataRefClass = getIrClass(FqName("kotlin.wasm.internal.reftypes.dataref"))
|
||||||
val wasmDataRefType by lazy { wasmDataRefClass.defaultType }
|
val wasmDataRefType by lazy { wasmDataRefClass.defaultType }
|
||||||
|
|
||||||
|
val wasmAnyRefClass = getIrClass(FqName("kotlin.wasm.internal.reftypes.anyref"))
|
||||||
|
|
||||||
private val externalInterfaceClass = getIrClass(FqName("kotlin.wasm.internal.ExternalInterfaceType"))
|
private val externalInterfaceClass = getIrClass(FqName("kotlin.wasm.internal.ExternalInterfaceType"))
|
||||||
val externalInterfaceType by lazy { externalInterfaceClass.defaultType }
|
val externalInterfaceType by lazy { externalInterfaceClass.defaultType }
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -45,7 +45,7 @@ internal class WasmUsefulDeclarationProcessor(
|
|||||||
}
|
}
|
||||||
context.wasmSymbols.wasmClassId,
|
context.wasmSymbols.wasmClassId,
|
||||||
context.wasmSymbols.wasmInterfaceId,
|
context.wasmSymbols.wasmInterfaceId,
|
||||||
context.wasmSymbols.wasmRefCast,
|
context.wasmSymbols.refCast,
|
||||||
context.wasmSymbols.refTest -> {
|
context.wasmSymbols.refTest -> {
|
||||||
call.getTypeArgument(0)?.getClass()?.enqueue(from, "generic intrinsic ${call.symbol.owner.name}")
|
call.getTypeArgument(0)?.getClass()?.enqueue(from, "generic intrinsic ${call.symbol.owner.name}")
|
||||||
true
|
true
|
||||||
@@ -63,8 +63,8 @@ internal class WasmUsefulDeclarationProcessor(
|
|||||||
val op = WasmOp.valueOf(opString)
|
val op = WasmOp.valueOf(opString)
|
||||||
when (op.immediates.size) {
|
when (op.immediates.size) {
|
||||||
0 -> {
|
0 -> {
|
||||||
if (op == WasmOp.REF_TEST) {
|
if (op == WasmOp.REF_TEST || op == WasmOp.REF_TEST_STATIC) {
|
||||||
call.getTypeArgument(0)?.enqueueRuntimeClassOrAny(from, "REF_TEST")
|
call.getTypeArgument(0)?.enqueueRuntimeClassOrAny(from, "REF_TEST/REF_TEST_STATIC")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
|
|||||||
+40
-26
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.wasm.utils.*
|
|||||||
import org.jetbrains.kotlin.backend.wasm.utils.isCanonical
|
import org.jetbrains.kotlin.backend.wasm.utils.isCanonical
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.findUnitGetInstanceFunction
|
import org.jetbrains.kotlin.ir.backend.js.utils.findUnitGetInstanceFunction
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver
|
import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||||
@@ -312,9 +313,8 @@ class BodyGenerator(
|
|||||||
val receiver = call.dispatchReceiver!!
|
val receiver = call.dispatchReceiver!!
|
||||||
generateExpression(receiver)
|
generateExpression(receiver)
|
||||||
|
|
||||||
if (!receiver.type.getRuntimeClass(irBuiltIns).isSubclassOf(klass)) {
|
//TODO: check why it could be needed
|
||||||
body.buildRefCastStatic(toType = context.referenceGcType(klass.symbol))
|
generateRefCast(receiver.type, klass.defaultType)
|
||||||
}
|
|
||||||
|
|
||||||
body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0))
|
body.buildStructGet(context.referenceGcType(klass.symbol), WasmSymbol(0))
|
||||||
body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot))
|
body.buildStructGet(context.referenceVTableGcType(klass.symbol), WasmSymbol(vfSlot))
|
||||||
@@ -350,14 +350,31 @@ class BodyGenerator(
|
|||||||
body.buildGetUnit()
|
body.buildGetUnit()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateRefCast(type: IrType) {
|
private fun generateRefCast(fromType: IrType, toType: IrType) {
|
||||||
body.buildRefCastStatic(
|
if (!isDownCastAlwaysSuccessInRuntime(fromType, toType)) {
|
||||||
context.referenceGcType(type.getRuntimeClass(irBuiltIns).symbol)
|
body.buildRefCastStatic(
|
||||||
)
|
toType = context.referenceGcType(toType.getRuntimeClass(irBuiltIns).symbol)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTypeRTT(type: IrType) {
|
private fun generateRefTest(fromType: IrType, toType: IrType) {
|
||||||
body.buildRttCanon(context.referenceGcType(type.getRuntimeClass(irBuiltIns).symbol))
|
if (!isDownCastAlwaysSuccessInRuntime(fromType, toType)) {
|
||||||
|
body.buildRefTestStatic(
|
||||||
|
toType = context.referenceGcType(toType.getRuntimeClass(irBuiltIns).symbol)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
body.buildDrop()
|
||||||
|
body.buildConstI32(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isDownCastAlwaysSuccessInRuntime(fromType: IrType, toType: IrType): Boolean {
|
||||||
|
val upperBound = fromType.erasedUpperBound
|
||||||
|
if (upperBound != null && upperBound.symbol.isSubtypeOfClass(backendContext.wasmSymbols.wasmAnyRefClass)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fromType.getRuntimeClass(irBuiltIns).isSubclassOf(toType.getRuntimeClass(irBuiltIns))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if generated.
|
// Return true if generated.
|
||||||
@@ -412,14 +429,11 @@ class BodyGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmSymbols.wasmRefCast -> {
|
wasmSymbols.refCast -> {
|
||||||
generateRefCast(call.getTypeArgument(0)!!)
|
generateRefCast(
|
||||||
}
|
fromType = call.getValueArgument(0)!!.type,
|
||||||
|
toType = call.getTypeArgument(0)!!
|
||||||
wasmSymbols.refTest -> {
|
)
|
||||||
val toType = call.getTypeArgument(0)!!
|
|
||||||
generateTypeRTT(toType)
|
|
||||||
body.buildInstr(WasmOp.REF_TEST)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmSymbols.unboxIntrinsic -> {
|
wasmSymbols.unboxIntrinsic -> {
|
||||||
@@ -441,8 +455,7 @@ class BodyGenerator(
|
|||||||
val klass: IrClass = backendContext.inlineClassesUtils.getInlinedClass(toType)!!
|
val klass: IrClass = backendContext.inlineClassesUtils.getInlinedClass(toType)!!
|
||||||
val field = getInlineClassBackingField(klass)
|
val field = getInlineClassBackingField(klass)
|
||||||
|
|
||||||
generateTypeRTT(toType)
|
generateRefCast(fromType, toType)
|
||||||
body.buildRefCast()
|
|
||||||
generateInstanceFieldAccess(field)
|
generateInstanceFieldAccess(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,21 +629,22 @@ class BodyGenerator(
|
|||||||
val opString = function.getWasmOpAnnotation()
|
val opString = function.getWasmOpAnnotation()
|
||||||
if (opString != null) {
|
if (opString != null) {
|
||||||
val op = WasmOp.valueOf(opString)
|
val op = WasmOp.valueOf(opString)
|
||||||
var immediates = emptyArray<WasmImmediate>()
|
|
||||||
when (op.immediates.size) {
|
when (op.immediates.size) {
|
||||||
0 -> {
|
0 -> {
|
||||||
when (op) {
|
when (op) {
|
||||||
WasmOp.REF_TEST -> {
|
WasmOp.REF_TEST, WasmOp.REF_TEST_STATIC -> {
|
||||||
val toIrType = call.getTypeArgument(0)!!
|
generateRefTest(
|
||||||
// ref.test takes RTT as a second operand
|
fromType = call.getValueArgument(0)!!.type,
|
||||||
generateTypeRTT(toIrType)
|
toType = call.getTypeArgument(0)!!
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
body.buildInstr(op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
immediates = arrayOf(
|
val immediates = arrayOf(
|
||||||
when (val imm = op.immediates[0]) {
|
when (val imm = op.immediates[0]) {
|
||||||
WasmImmediateKind.MEM_ARG ->
|
WasmImmediateKind.MEM_ARG ->
|
||||||
WasmImmediate.MemArg(0u, 0u)
|
WasmImmediate.MemArg(0u, 0u)
|
||||||
@@ -643,11 +657,11 @@ class BodyGenerator(
|
|||||||
error("Immediate $imm is unsupported")
|
error("Immediate $imm is unsupported")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
body.buildInstr(op, *immediates)
|
||||||
}
|
}
|
||||||
else ->
|
else ->
|
||||||
error("Op $opString is unsupported")
|
error("Op $opString is unsupported")
|
||||||
}
|
}
|
||||||
body.buildInstr(op, *immediates)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -9,11 +9,14 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
|||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.builders.buildStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irImplicitCast
|
import org.jetbrains.kotlin.ir.builders.irImplicitCast
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||||
import org.jetbrains.kotlin.ir.types.isAny
|
import org.jetbrains.kotlin.ir.types.isAny
|
||||||
|
|||||||
+1
-1
@@ -580,7 +580,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
|
|||||||
) : InteropTypeAdapter {
|
) : InteropTypeAdapter {
|
||||||
override val fromType: IrType = context.wasmSymbols.wasmDataRefType
|
override val fromType: IrType = context.wasmSymbols.wasmDataRefType
|
||||||
override fun adapt(expression: IrExpression, builder: IrBuilderWithScope): IrExpression {
|
override fun adapt(expression: IrExpression, builder: IrBuilderWithScope): IrExpression {
|
||||||
val call = builder.irCall(context.wasmSymbols.wasmRefCast)
|
val call = builder.irCall(context.wasmSymbols.refCast)
|
||||||
call.putValueArgument(0, expression)
|
call.putValueArgument(0, expression)
|
||||||
call.putTypeArgument(0, toType)
|
call.putTypeArgument(0, toType)
|
||||||
return call
|
return call
|
||||||
|
|||||||
+2
-1
@@ -225,6 +225,7 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
|
|||||||
if (fromClass.isSubclassOf(toClass)) {
|
if (fromClass.isSubclassOf(toClass)) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toType.isNothing()) {
|
if (toType.isNothing()) {
|
||||||
// Casting to nothing is unreachable...
|
// Casting to nothing is unreachable...
|
||||||
return builder.irComposite(resultType = context.irBuiltIns.nothingType) {
|
return builder.irComposite(resultType = context.irBuiltIns.nothingType) {
|
||||||
@@ -233,7 +234,7 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.irCall(symbols.wasmRefCast, type = toType).apply {
|
return builder.irCall(symbols.refCast, type = toType).apply {
|
||||||
putTypeArgument(0, toType)
|
putTypeArgument(0, toType)
|
||||||
putValueArgument(0, value)
|
putValueArgument(0, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,15 +150,14 @@ abstract class WasmExpressionBuilder {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun buildRefCast() {
|
|
||||||
buildInstr(WasmOp.REF_CAST)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildRefCastStatic(toType: WasmSymbolReadOnly<WasmTypeDeclaration>) {
|
fun buildRefCastStatic(toType: WasmSymbolReadOnly<WasmTypeDeclaration>) {
|
||||||
buildInstr(WasmOp.REF_CAST_STATIC, WasmImmediate.TypeIdx(toType))
|
buildInstr(WasmOp.REF_CAST_STATIC, WasmImmediate.TypeIdx(toType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildRefTestStatic(toType: WasmSymbolReadOnly<WasmTypeDeclaration>) {
|
||||||
|
buildInstr(WasmOp.REF_TEST_STATIC, WasmImmediate.TypeIdx(toType))
|
||||||
|
}
|
||||||
|
|
||||||
fun buildRefNull(type: WasmHeapType) {
|
fun buildRefNull(type: WasmHeapType) {
|
||||||
buildInstr(WasmOp.REF_NULL, WasmImmediate.HeapType(WasmRefType(type)))
|
buildInstr(WasmOp.REF_NULL, WasmImmediate.HeapType(WasmRefType(type)))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user