From d1c81eb6baa05e9c10cb14dad9fef7c9e8873cc8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Wed, 16 Feb 2022 15:01:31 +0300 Subject: [PATCH] [Wasm] Support Wasm GC milestone 5 --- .../dce/WasmUsefulDeclarationProcessor.kt | 3 +- .../backend/wasm/ir2wasm/BodyGenerator.kt | 22 ++++++++-- .../wasm/ir2wasm/DeclarationGenerator.kt | 44 ++++--------------- .../backend/wasm/ir2wasm/TypeTransformer.kt | 4 +- .../wasm/ir2wasm/WasmBaseCodegenContext.kt | 1 - .../ir2wasm/WasmCompiledModuleFragment.kt | 42 ++++++++++++------ .../wasm/ir2wasm/WasmModuleCodegenContext.kt | 1 - .../ir2wasm/WasmModuleCodegenContextImpl.kt | 7 --- .../wasm/lower/GenericReturnTypeLowering.kt | 8 ---- .../function/covariantOverride.kt | 4 -- .../function/covariantOverrideGeneric.kt | 4 -- .../coercionToUnitWithLastLambdaExpression.kt | 1 + .../codegen/boxWasmJsInterop/functionTypes.kt | 2 + js/js.tests/build.gradle.kts | 2 +- .../kotlin/js/testOld/BasicWasmBoxTest.kt | 1 - .../accessToCompanionObjectFromInlineFun.kt | 3 ++ .../testData/box/native/classObject.kt | 3 ++ .../passTopLevelOrLocalFunctionToNative.kt | 3 ++ .../jetbrains/kotlin/wasm/ir/Declarations.kt | 15 ++++--- .../org/jetbrains/kotlin/wasm/ir/Operators.kt | 7 ++- .../src/org/jetbrains/kotlin/wasm/ir/Types.kt | 12 ++--- .../kotlin/wasm/ir/WasmExpressionBuilder.kt | 8 ++-- .../wasm/ir/convertors/WasmBinaryToIR.kt | 9 ++-- .../wasm/ir/convertors/WasmIrToBinary.kt | 19 +++++--- .../kotlin/wasm/ir/convertors/WasmIrToText.kt | 30 ++++++++++--- 25 files changed, 140 insertions(+), 115 deletions(-) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/dce/WasmUsefulDeclarationProcessor.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/dce/WasmUsefulDeclarationProcessor.kt index ae76be30b28..ac690f68ff1 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/dce/WasmUsefulDeclarationProcessor.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/dce/WasmUsefulDeclarationProcessor.kt @@ -45,7 +45,8 @@ internal class WasmUsefulDeclarationProcessor( } context.wasmSymbols.wasmClassId, context.wasmSymbols.wasmInterfaceId, - context.wasmSymbols.wasmRefCast -> { + context.wasmSymbols.wasmRefCast, + context.wasmSymbols.refTest -> { call.getTypeArgument(0)?.getClass()?.enqueue(from, "generic intrinsic ${call.symbol.owner.name}") true } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index 227bdfb113f..5acc0a6f0ac 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid @@ -213,7 +214,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV generateDefaultInitializerForType(context.transformType(field.type), body) } - body.buildGetGlobal(context.referenceClassRTT(klass.symbol)) + generateClassRTT(klass.symbol) body.buildStructNew(wasmGcType) generateCall(expression) } @@ -243,7 +244,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV body.buildConstI32Symbol(klassId) body.buildConstI32(0) // Any::_hashCode generateExpression(call.getValueArgument(0)!!) - body.buildGetGlobal(context.referenceClassRTT(klass.symbol)) + generateClassRTT(klass.symbol) body.buildStructNew(structTypeName) return } @@ -322,8 +323,12 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV } private fun generateTypeRTT(type: IrType) { - val rtClass = type.getRuntimeClass?.symbol ?: context.backendContext.irBuiltIns.anyClass - body.buildGetGlobal(context.referenceClassRTT(rtClass)) + val klass = type.getRuntimeClass?.symbol ?: context.backendContext.irBuiltIns.anyClass + generateClassRTT(klass) + } + + private fun generateClassRTT(klass: IrClassSymbol) { + body.buildRttCanon(context.referenceGcType(klass)) } // Return true if generated. @@ -357,6 +362,12 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV body.buildRefCast() } + wasmSymbols.refTest -> { + val toType = call.getTypeArgument(0)!! + generateTypeRTT(toType) + body.buildInstr(WasmOp.REF_TEST) + } + wasmSymbols.unboxIntrinsic -> { val fromType = call.getTypeArgument(0)!! @@ -581,6 +592,9 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV WasmImmediate.MemArg(0u, 0u) WasmImmediateKind.STRUCT_TYPE_IDX -> WasmImmediate.GcType(context.referenceGcType(function.dispatchReceiverParameter!!.type.classOrNull!!)) + WasmImmediateKind.TYPE_IDX -> + WasmImmediate.TypeIdx(context.referenceGcType(function.dispatchReceiverParameter!!.type.classOrNull!!)) + else -> error("Immediate $imm is unsupported") } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt index 88c5979caeb..7866babbe11 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt @@ -85,7 +85,6 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al val wasmFunctionType = WasmFunctionType( - name = watName, parameterTypes = irParameters.map { context.transformValueParameterType(it) }, resultTypes = listOfNotNull(resultType) ) @@ -104,17 +103,19 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al "Sanity check that $declaration is a real function that can be used in calls" } + val functionTypeSymbol = context.referenceFunctionType(declaration.symbol) + if (importedName != null) { // Imported functions don't have bodies. Declaring the signature: context.defineFunction( declaration.symbol, - WasmFunction.Imported(watName, wasmFunctionType, importedName) + WasmFunction.Imported(watName, functionTypeSymbol, importedName) ) // TODO: Support re-export of imported functions. return } - val function = WasmFunction.Defined(watName, wasmFunctionType) + val function = WasmFunction.Defined(watName, functionTypeSymbol) val functionCodegenContext = WasmFunctionCodegenContextImpl( declaration, function, @@ -200,6 +201,8 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al context.registerInterface(symbol) } else { val nameStr = declaration.fqNameWhenAvailable.toString() + val metadata = context.getClassMetadata(symbol) + val superClass = metadata.superClass val structType = WasmStructDeclaration( name = nameStr, fields = declaration.allFields(irBuiltIns).map { @@ -208,40 +211,11 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext, private val al type = context.transformFieldType(it.type), isMutable = true ) - } + }, + superClass?.let { context.referenceGcType(superClass.klass.symbol) } ) context.defineGcType(symbol, structType) - - var depth = 0 - val metadata = context.getClassMetadata(symbol) - var subMetadata = metadata - while (true) { - subMetadata = subMetadata.superClass ?: break - depth++ - } - - val initBody = mutableListOf() - val wasmExpressionGenerator = WasmIrExpressionBuilder(initBody) - - val wasmGcType = context.referenceGcType(symbol) - val superClass = metadata.superClass - if (superClass != null) { - val superRTT = context.referenceClassRTT(superClass.klass.symbol) - wasmExpressionGenerator.buildGetGlobal(superRTT) - wasmExpressionGenerator.buildRttSub(wasmGcType) - } else { - wasmExpressionGenerator.buildRttCanon(wasmGcType) - } - - val rtt = WasmGlobal( - name = "rtt_of_$nameStr", - isMutable = false, - type = WasmRtt(depth, WasmSymbol(structType)), - init = initBody - ) - - context.defineRTT(symbol, rtt) context.registerClass(symbol) context.generateTypeInfo(symbol, binaryDataStruct(metadata)) @@ -394,7 +368,7 @@ fun generateDefaultInitializerForType(type: WasmType, g: WasmExpressionBuilder) WasmF32 -> g.buildConstF32(0f) WasmF64 -> g.buildConstF64(0.0) is WasmRefNullType -> g.buildRefNull(type.heapType) - is WasmExternRef, is WasmAnyRef -> g.buildRefNull(WasmHeapType.Simple.Extern) + is WasmAnyRef -> g.buildRefNull(WasmHeapType.Simple.Extern) WasmUnreachableType -> error("Unreachable type can't be initialized") else -> error("Unknown value type ${type.name}") } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt index f787b5729dc..b3bb08ffdd0 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt @@ -82,11 +82,11 @@ class WasmTypeTransformer( WasmF64 builtIns.nothingNType -> - WasmExternRef + WasmAnyRef // Value will not be created. Just using a random Wasm type. builtIns.nothingType -> - WasmExternRef + WasmAnyRef symbols.voidType -> error("Void type can't be used as a value") diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt index 7c1678b736c..97e78c593be 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmBaseCodegenContext.kt @@ -29,7 +29,6 @@ interface WasmBaseCodegenContext { fun referenceClassId(irClass: IrClassSymbol): WasmSymbol fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol fun referenceVirtualFunctionId(irFunction: IrSimpleFunctionSymbol): WasmSymbol - fun referenceClassRTT(irClass: IrClassSymbol): WasmSymbol fun referenceSignatureId(signature: WasmSignature): WasmSymbol diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt index 0b343f688d7..c7b48e45a77 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.backend.wasm.ir2wasm -import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName @@ -35,11 +34,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) { val stringLiteralId = ReferencableElements() - val runtimeTypes = - ReferencableAndDefinable() - val tagFuncType = WasmFunctionType( - "ex_handling_tag", listOf( WasmRefNullType(WasmHeapType.Type(gcTypes.reference(irBuiltIns.throwableClass))) ), @@ -123,9 +118,18 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) { fun linkWasmCompiledFragments(): WasmModule { bind(functions.unbound, functions.defined) bind(globals.unbound, globals.defined) - bind(functionTypes.unbound, functionTypes.defined) + bind(gcTypes.unbound, gcTypes.defined) - bind(runtimeTypes.unbound, runtimeTypes.defined) + + // Associate function types to a single canonical function type + val canonicalFunctionTypes = + functionTypes.elements.associateWithTo(LinkedHashMap()) { it } + + functionTypes.unbound.forEach { (irSymbol, wasmSymbol) -> + if (irSymbol !in functionTypes.defined) + error("Can't link symbol ${irSymbolDebugDump(irSymbol)}") + wasmSymbol.bind(canonicalFunctionTypes.getValue(functionTypes.defined.getValue(irSymbol))) + } val klassIds = mutableMapOf() var currentDataSectionAddress = 0 @@ -260,8 +264,8 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) { ) } - val masterInitFunctionType = WasmFunctionType("__init_t", emptyList(), emptyList()) - val masterInitFunction = WasmFunction.Defined("__init", masterInitFunctionType) + val masterInitFunctionType = WasmFunctionType(emptyList(), emptyList()) + val masterInitFunction = WasmFunction.Defined("__init", WasmSymbol(masterInitFunctionType)) with(WasmIrExpressionBuilder(masterInitFunction.instructions)) { initFunctions.sortedBy { it.priority }.forEach { buildCall(WasmSymbol(it.function)) @@ -283,18 +287,28 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) { val importedFunctions = functions.elements.filterIsInstance() - // Sorting by depth for a valid init order - val sortedRttGlobals = runtimeTypes.elements.sortedBy { (it.type as WasmRtt).depth } + fun wasmTypeDeclarationOrderKey(declaration: WasmTypeDeclaration): Int { + return when (declaration) { + is WasmArrayDeclaration -> 0 + is WasmFunctionType -> 0 + is WasmStructDeclaration -> + // Subtype depth + declaration.superType?.let { wasmTypeDeclarationOrderKey(it.owner) + 1 } ?: 0 + } + } + + val sortedGcTypes = gcTypes.elements.sortedBy(::wasmTypeDeclarationOrderKey) val module = WasmModule( - functionTypes = functionTypes.elements + tagFuncType + masterInitFunctionType, - gcTypes = gcTypes.elements, + functionTypes = canonicalFunctionTypes.values.toList() + tagFuncType + masterInitFunctionType, + gcTypes = sortedGcTypes, + gcTypesInRecursiveGroup = true, importsInOrder = importedFunctions, importedFunctions = importedFunctions, definedFunctions = functions.elements.filterIsInstance() + masterInitFunction, tables = listOf(table) + interfaceMethodTables.elements, memories = listOf(memory), - globals = globals.elements + sortedRttGlobals, + globals = globals.elements, exports = exports, startFunction = null, // Module is initialized via export call elements = listOf(elements) + interfaceTableElements, diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt index 8048b95d733..a3803c3f619 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt @@ -18,7 +18,6 @@ interface WasmModuleCodegenContext : WasmBaseCodegenContext { fun defineFunction(irFunction: IrFunctionSymbol, wasmFunction: WasmFunction) fun defineGlobal(irField: IrFieldSymbol, wasmGlobal: WasmGlobal) fun defineGcType(irClass: IrClassSymbol, wasmType: WasmTypeDeclaration) - fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal) fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType) fun defineInterfaceMethodTable(irFunction: IrFunctionSymbol, wasmTable: WasmTable) fun addJsFun(importName: String, jsCode: String) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt index 2d62e5f306b..7c32ae92140 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContextImpl.kt @@ -106,10 +106,6 @@ class WasmModuleCodegenContextImpl( wasmFragment.gcTypes.define(irClass, wasmType) } - override fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal) { - wasmFragment.runtimeTypes.define(irClass, wasmGlobal) - } - override fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType) { wasmFragment.functionTypes.define(irFunction, wasmFunctionType) } @@ -157,9 +153,6 @@ class WasmModuleCodegenContextImpl( return wasmFragment.gcTypes.reference(irClass) } - override fun referenceClassRTT(irClass: IrClassSymbol): WasmSymbol = - wasmFragment.runtimeTypes.reference(irClass) - override fun referenceFunctionType(irFunction: IrFunctionSymbol): WasmSymbol = wasmFragment.functionTypes.reference(irFunction) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/GenericReturnTypeLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/GenericReturnTypeLowering.kt index c8f89931e40..b384b05a8db 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/GenericReturnTypeLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/GenericReturnTypeLowering.kt @@ -51,9 +51,6 @@ class GenericReturnTypeLowering(val context: WasmBackendContext) : FileLoweringP val function: IrSimpleFunction = call.symbol.owner as? IrSimpleFunction ?: return call - if (!function.realOverrideTarget.returnType.isTypeParameter()) - return call - val erasedReturnType: IrType = function.realOverrideTarget.returnType.eraseUpperBoundType() @@ -72,11 +69,6 @@ class GenericReturnTypeLowering(val context: WasmBackendContext) : FileLoweringP ) context.createIrBuilder(scopeOwnerSymbol).apply { - if (call.type.isUnit()) { - return irComposite(call) { - +newCall - } - } return irImplicitCast(newCall, call.type) } } diff --git a/compiler/testData/codegen/box/defaultArguments/function/covariantOverride.kt b/compiler/testData/codegen/box/defaultArguments/function/covariantOverride.kt index 5bd56f1b483..fddf1012253 100644 --- a/compiler/testData/codegen/box/defaultArguments/function/covariantOverride.kt +++ b/compiler/testData/codegen/box/defaultArguments/function/covariantOverride.kt @@ -1,7 +1,3 @@ -// IGNORE_BACKEND: WASM -// WASM_MUTE_REASON: FAKE_OVERRIDE_ISSUES -// On wasm this will produce conflicting return types, foo will return Any but we will try to interpret it as String. -// Before wasm native strings this worked by chance because we added unbox intrinsic for strings. open class Foo { open fun foo(x: CharSequence = "O"): CharSequence = x diff --git a/compiler/testData/codegen/box/defaultArguments/function/covariantOverrideGeneric.kt b/compiler/testData/codegen/box/defaultArguments/function/covariantOverrideGeneric.kt index f04dcc94e94..c982d8ac7f9 100644 --- a/compiler/testData/codegen/box/defaultArguments/function/covariantOverrideGeneric.kt +++ b/compiler/testData/codegen/box/defaultArguments/function/covariantOverrideGeneric.kt @@ -1,7 +1,3 @@ -// IGNORE_BACKEND: WASM -// WASM_MUTE_REASON: FAKE_OVERRIDE_ISSUES -// On wasm this will produce conflicting return types, foo will return Any but we will try to interpret it as String. -// Before wasm native strings this worked by chance because we added unbox intrinsic for strings. open class Foo { open fun foo(x: CharSequence = "O"): CharSequence = x diff --git a/compiler/testData/codegen/box/inference/coercionToUnitWithLastLambdaExpression.kt b/compiler/testData/codegen/box/inference/coercionToUnitWithLastLambdaExpression.kt index 11590ac5d57..d77a0ac9416 100644 --- a/compiler/testData/codegen/box/inference/coercionToUnitWithLastLambdaExpression.kt +++ b/compiler/testData/codegen/box/inference/coercionToUnitWithLastLambdaExpression.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: WASM fun myRun(action: () -> T): T = action() fun foo(): String = "foo" diff --git a/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt b/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt index 329094878ae..f5a5ed9e849 100644 --- a/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt +++ b/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt @@ -1,3 +1,5 @@ +// V8 fail: https://bugs.chromium.org/p/v8/issues/detail?id=12834 +// IGNORE_BACKEND: WASM // Char issues // IGNORE_BACKEND: JS_IR diff --git a/js/js.tests/build.gradle.kts b/js/js.tests/build.gradle.kts index ebd368297a8..f2fb9db123b 100644 --- a/js/js.tests/build.gradle.kts +++ b/js/js.tests/build.gradle.kts @@ -158,7 +158,7 @@ val v8osString = when (currentOsType) { } val v8edition = "rel" // rel or dbg -val v8version = "9.2.212" +val v8version = "10.2.9" val v8fileName = "v8-${v8osString}-${v8edition}-${v8version}" val v8url = "https://storage.googleapis.com/chromium-v8/official/canary/$v8fileName.zip" diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt index d5ccde54ed0..3afd3f17d30 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt @@ -180,7 +180,6 @@ abstract class BasicWasmBoxTest( File(dir, "test.js").writeText(testJs) ExternalTool(System.getProperty("javascript.engine.path.V8")) .run( - "--experimental-wasm-typed-funcref", "--experimental-wasm-gc", "--experimental-wasm-eh", *jsFilesBefore.map { File(it).absolutePath }.toTypedArray(), diff --git a/js/js.translator/testData/box/native/accessToCompanionObjectFromInlineFun.kt b/js/js.translator/testData/box/native/accessToCompanionObjectFromInlineFun.kt index 5b48452e051..c1f9384cb6c 100644 --- a/js/js.translator/testData/box/native/accessToCompanionObjectFromInlineFun.kt +++ b/js/js.translator/testData/box/native/accessToCompanionObjectFromInlineFun.kt @@ -1,3 +1,6 @@ +// V8 fail: https://bugs.chromium.org/p/v8/issues/detail?id=12834 +// IGNORE_BACKEND: WASM + // EXPECTED_REACHABLE_NODES: 1281 // FILE: main.kt diff --git a/js/js.translator/testData/box/native/classObject.kt b/js/js.translator/testData/box/native/classObject.kt index 378e3ba8cdf..7ea549a71ec 100644 --- a/js/js.translator/testData/box/native/classObject.kt +++ b/js/js.translator/testData/box/native/classObject.kt @@ -1,3 +1,6 @@ +// V8 fail: https://bugs.chromium.org/p/v8/issues/detail?id=12834 +// IGNORE_BACKEND: WASM + // EXPECTED_REACHABLE_NODES: 1283 package foo diff --git a/js/js.translator/testData/box/native/passTopLevelOrLocalFunctionToNative.kt b/js/js.translator/testData/box/native/passTopLevelOrLocalFunctionToNative.kt index d94bde8bc62..0b951944e0b 100644 --- a/js/js.translator/testData/box/native/passTopLevelOrLocalFunctionToNative.kt +++ b/js/js.translator/testData/box/native/passTopLevelOrLocalFunctionToNative.kt @@ -1,3 +1,6 @@ +// V8 fail: https://bugs.chromium.org/p/v8/issues/detail?id=12834 +// IGNORE_BACKEND: WASM + // EXPECTED_REACHABLE_NODES: 1284 package foo diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt index c0492dead72..706b5326ce8 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt @@ -9,6 +9,7 @@ package org.jetbrains.kotlin.wasm.ir class WasmModule( val functionTypes: List = emptyList(), val gcTypes: List = emptyList(), + val gcTypesInRecursiveGroup: Boolean, val importsInOrder: List = emptyList(), val importedFunctions: List = emptyList(), @@ -38,18 +39,18 @@ sealed class WasmNamedModuleField { sealed class WasmFunction( override val name: String, - val type: WasmFunctionType + val type: WasmSymbolReadOnly ) : WasmNamedModuleField() { class Defined( name: String, - type: WasmFunctionType, + type: WasmSymbolReadOnly, val locals: MutableList = mutableListOf(), val instructions: MutableList = mutableListOf() ) : WasmFunction(name, type) class Imported( name: String, - type: WasmFunctionType, + type: WasmSymbolReadOnly, val importPair: WasmImportPair ) : WasmFunction(name, type) } @@ -146,15 +147,15 @@ sealed class WasmTypeDeclaration( override val name: String ) : WasmNamedModuleField() -class WasmFunctionType( - name: String, +data class WasmFunctionType( val parameterTypes: List, val resultTypes: List -) : WasmTypeDeclaration(name) +) : WasmTypeDeclaration("") class WasmStructDeclaration( name: String, - val fields: List + val fields: List, + val superType: WasmSymbolReadOnly? ) : WasmTypeDeclaration(name) class WasmArrayDeclaration( diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt index 18965959c54..1e549e4115b 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Operators.kt @@ -343,6 +343,8 @@ enum class WasmOp( // GC STRUCT_NEW_WITH_RTT("struct.new_with_rtt", 0xFB_01, STRUCT_TYPE_IDX), STRUCT_NEW_DEFAULT_WITH_RTT("struct.new_default_with_rtt", 0xFB_02, STRUCT_TYPE_IDX), + STRUCT_NEW("struct.new", 0xFB_07, STRUCT_TYPE_IDX), + STRUCT_NEW_DEFAULT("struct.new_default", 0xFB_08, STRUCT_TYPE_IDX), STRUCT_GET("struct.get", 0xFB_03, listOf(STRUCT_TYPE_IDX, STRUCT_FIELD_IDX)), STRUCT_GET_S("struct.get_s", 0xFB_04, listOf(STRUCT_TYPE_IDX, STRUCT_FIELD_IDX)), STRUCT_GET_U("struct.get_u", 0xFB_05, listOf(STRUCT_TYPE_IDX, STRUCT_FIELD_IDX)), @@ -350,6 +352,8 @@ enum class WasmOp( ARRAY_NEW_WITH_RTT("array.new_with_rtt", 0xFB_11, STRUCT_TYPE_IDX), ARRAY_NEW_DEFAULT_WITH_RTT("array.new_default_with_rtt", 0xFB_12, STRUCT_TYPE_IDX), + ARRAY_NEW("array.new", 0xFB_1B, STRUCT_TYPE_IDX), + ARRAY_NEW_DEFAULT("array.new_default", 0xFB_1C, STRUCT_TYPE_IDX), ARRAY_GET("array.get", 0xFB_13, listOf(STRUCT_TYPE_IDX)), ARRAY_GET_S("array.get_s", 0xFB_14, listOf(STRUCT_TYPE_IDX)), ARRAY_GET_U("array.get_u", 0xFB_15, listOf(STRUCT_TYPE_IDX)), @@ -362,9 +366,10 @@ enum class WasmOp( RTT_CANON("rtt.canon", 0xFB_30, TYPE_IDX), - RTT_SUB("rtt.sub", 0xFB_31, TYPE_IDX), REF_TEST("ref.test", 0xFB_40), + REF_TEST_STATIC("ref.test_static", 0xFB_44, STRUCT_TYPE_IDX), REF_CAST("ref.cast", 0xFB_41), + REF_CAST_STATIC("ref.cast_static", 0xFB_45, STRUCT_TYPE_IDX), BR_ON_CAST("br_on_cast", 0xFB_42, listOf(LABEL_IDX)), diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt index b719cc07f0d..769db51fde1 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Types.kt @@ -26,18 +26,18 @@ object WasmExternRef : WasmType("externref", -0x11) object WasmAnyRef : WasmType("anyref", -0x12) object WasmEqRef : WasmType("eqref", -0x13) -class WasmRefNullType(val heapType: WasmHeapType) : WasmType("ref null", -0x14) -class WasmRefType(val heapType: WasmHeapType) : WasmType("ref", -0x15) +data class WasmRefNullType(val heapType: WasmHeapType) : WasmType("ref null", -0x14) +data class WasmRefType(val heapType: WasmHeapType) : WasmType("ref", -0x15) @Suppress("unused") object WasmI31Ref : WasmType("i31ref", -0x16) -class WasmRtt(val depth: Int, val type: WasmSymbolReadOnly) : WasmType("rtt", -0x17) +data class WasmRtt(val type: WasmSymbolReadOnly) : WasmType("rtt", -0x18) @Suppress("unused") object WasmDataRef : WasmType("dataref", -0x19) sealed class WasmHeapType { - class Type(val type: WasmSymbolReadOnly) : WasmHeapType() { + data class Type(val type: WasmSymbolReadOnly) : WasmHeapType() { override fun toString(): String { return "Type:$type" } @@ -46,6 +46,7 @@ sealed class WasmHeapType { sealed class Simple(val name: String, val code: Byte) : WasmHeapType() { object Func : Simple("func", -0x10) object Extern : Simple("extern", -0x11) + object Any : Simple("any", -0x12) object Eq : Simple("eq", -0x13) @Suppress("unused") @@ -70,7 +71,8 @@ fun WasmType.getHeapType(): WasmHeapType = is WasmRefType -> heapType is WasmRefNullType -> heapType is WasmEqRef -> WasmHeapType.Simple.Eq - is WasmExternRef -> WasmHeapType.Simple.Extern + is WasmAnyRef -> WasmHeapType.Simple.Any is WasmFuncRef -> WasmHeapType.Simple.Func + is WasmExternRef -> WasmHeapType.Simple.Extern else -> error("Unknown heap type for type $this") } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt index 14b56953518..6eacbfe3a4d 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/WasmExpressionBuilder.kt @@ -142,12 +142,12 @@ abstract class WasmExpressionBuilder { buildInstr(WasmOp.REF_CAST) } - fun buildRefNull(type: WasmHeapType) { - buildInstr(WasmOp.REF_NULL, WasmImmediate.HeapType(WasmRefType(type))) + fun buildRefCastStatic(type: WasmSymbolReadOnly) { + buildInstr(WasmOp.REF_CAST_STATIC, WasmImmediate.TypeIdx(type)) } - fun buildRttSub(decl: WasmSymbol) { - buildInstr(WasmOp.RTT_SUB, WasmImmediate.TypeIdx(decl)) + fun buildRefNull(type: WasmHeapType) { + buildInstr(WasmOp.REF_NULL, WasmImmediate.HeapType(WasmRefType(type))) } fun buildRttCanon(decl: WasmSymbol) { diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmBinaryToIR.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmBinaryToIR.kt index e0346e7d94a..44ef6cab879 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmBinaryToIR.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmBinaryToIR.kt @@ -97,7 +97,7 @@ class WasmBinaryToIR(val b: MyByteReader) { val type = functionTypes[b.readVarUInt32AsInt()] importedFunctions += WasmFunction.Imported( name = "", - type = type, + type = WasmSymbol(type), importPair = importPair, ).also { importsInOrder.add(it) } } @@ -141,7 +141,7 @@ class WasmBinaryToIR(val b: MyByteReader) { definedFunctions.add( WasmFunction.Defined( "", - functionType, + WasmSymbol(functionType), locals = functionType.parameterTypes.mapIndexed { index, wasmType -> WasmLocal(index, "", wasmType, true) }.toMutableList() @@ -330,6 +330,7 @@ class WasmBinaryToIR(val b: MyByteReader) { return WasmModule( functionTypes = functionTypes, gcTypes = gcTypes, + gcTypesInRecursiveGroup = false, importsInOrder = importsInOrder, importedFunctions = importedFunctions, importedMemories = importedMemories, @@ -450,7 +451,7 @@ class WasmBinaryToIR(val b: MyByteReader) { (-0x20).toByte() -> { val types = mapVector { readValueType() } val returnTypes = mapVector { readValueType() } - return WasmFunctionType("", types, returnTypes) + return WasmFunctionType(types, returnTypes) } else -> TODO() @@ -466,8 +467,8 @@ class WasmBinaryToIR(val b: MyByteReader) { WasmI8, WasmI16, WasmFuncRef, - WasmExternRef, WasmAnyRef, + WasmExternRef, WasmEqRef ).associateBy { it.code } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt index 057f19857f2..0391d44b6ad 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt @@ -21,13 +21,17 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod with(module) { // type section appendSection(1u) { + if (module.gcTypesInRecursiveGroup) { + appendVectorSize(1) + b.writeByte(0x4f) + } appendVectorSize(functionTypes.size + gcTypes.size) functionTypes.forEach { appendFunctionTypeDeclaration(it) } gcTypes.forEach { when (it) { is WasmStructDeclaration -> appendStructTypeDeclaration(it) is WasmArrayDeclaration -> appendArrayTypeDeclaration(it) - is WasmFunctionType -> {} + is WasmFunctionType -> error("Function type in GC types") } } } @@ -277,6 +281,12 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod } private fun appendStructTypeDeclaration(type: WasmStructDeclaration) { + val superType = type.superType + if (superType != null) { + b.writeVarInt7(-0x30) + appendVectorSize(1) + appendModuleFieldReference(superType.owner) + } b.writeVarInt7(-0x21) b.writeVarUInt32(type.fields.size) type.fields.forEach { @@ -290,7 +300,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod } val WasmFunctionType.index: Int - get() = module.functionTypes.indexOf(this) + get() = id!! private fun appendLimits(limits: WasmLimits) { b.writeVarUInt1(limits.maxSize != null) @@ -303,11 +313,11 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod b.writeString(function.importPair.moduleName) b.writeString(function.importPair.declarationName) b.writeByte(0) // Function external kind. - b.writeVarUInt32(function.type.index) + b.writeVarUInt32(function.type.owner.index) } private fun appendDefinedFunction(function: WasmFunction.Defined) { - b.writeVarUInt32(function.type.index) + b.writeVarUInt32(function.type.owner.index) } private fun appendTable(table: WasmTable) { @@ -483,7 +493,6 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod appendHeapType(type.heapType) } if (type is WasmRtt) { - b.writeVarUInt32(type.depth) appendModuleFieldReference(type.type.owner) } } diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt index 3e80118dfdd..82bbee2f53a 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt @@ -246,12 +246,26 @@ class WasmIrToText : SExpressionBuilder() { } } + private inline fun maybeSubType(superType: WasmTypeDeclaration?, body: () -> Unit) { + if (superType != null) { + sameLineList("sub") { + appendModuleFieldReference(superType) + body() + } + } else { + body() + } + } + + private fun appendStructTypeDeclaration(type: WasmStructDeclaration) { newLineList("type") { appendModuleFieldReference(type) - sameLineList("struct") { - type.fields.forEach { - appendStructField(it) + maybeSubType(type.superType?.owner) { + sameLineList("struct") { + type.fields.forEach { + appendStructField(it) + } } } } @@ -287,9 +301,9 @@ class WasmIrToText : SExpressionBuilder() { appendModuleFieldReference(function) sameLineList("type") { appendModuleFieldReference(function.type) } function.locals.forEach { if (it.isParameter) appendLocal(it) } - if (function.type.resultTypes.isNotEmpty()) { + if (function.type.owner.resultTypes.isNotEmpty()) { sameLineList("result") { - function.type.resultTypes.forEach { appendType(it) } + function.type.owner.resultTypes.forEach { appendType(it) } } } function.locals.forEach { if (!it.isParameter) appendLocal(it) } @@ -438,6 +452,7 @@ class WasmIrToText : SExpressionBuilder() { fun appendReferencedType(type: WasmType) { when (type) { is WasmFuncRef -> appendElement("func") + is WasmAnyRef -> appendElement("any") is WasmExternRef -> appendElement("extern") else -> TODO() } @@ -457,7 +472,6 @@ class WasmIrToText : SExpressionBuilder() { is WasmRtt -> sameLineList("rtt") { - appendElement(type.depth.toString()) appendModuleFieldReference(type.type.owner) } @@ -489,6 +503,10 @@ class WasmIrToText : SExpressionBuilder() { if (id != 0) appendElement(id.toString()) } + fun appendModuleFieldReference(field: WasmSymbolReadOnly) { + appendModuleFieldReference(field.owner) + } + fun appendModuleFieldReference(field: WasmNamedModuleField) { val id = field.id ?: error("${field::class} ${field.name} ID is unlinked")