From 2e26b0956e78d79e23536fec4d794b106cc1438c Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Fri, 3 Feb 2023 06:55:59 +0000 Subject: [PATCH] [Wasm] Improve stability of wasm import names across compiler runs Remove code generation for external fake overrides Fake overrides are resolved to real declaration on call sites This also removes generation of unused "equals", "hashCode" and "toString" methods. Avoid using hashes of IrType in generated code because they are unstable Merge-request: KT-MR-8658 Merged-by: Svyatoslav Kuzmich --- .../backend/wasm/ir2wasm/DeclarationGenerator.kt | 14 +++++++++----- ...ernalDeclarationsToTopLevelFunctionsLowering.kt | 4 ++++ .../wasm/lower/JsInteropFunctionsLowering.kt | 4 +++- .../testData/box/native/nestedElements.kt | 1 - 4 files changed, 16 insertions(+), 7 deletions(-) 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 af7902c53f1..c8e95c9959d 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 @@ -53,11 +53,16 @@ class DeclarationGenerator( // Type aliases are not material } + + private val jsCodeCounter = mutableMapOf() private fun jsCodeName(declaration: IrFunction): String { require(declaration is IrSimpleFunction) - val fqName = declaration.fqNameWhenAvailable!!.asString() - val hashCode = declaration.wasmSignature(irBuiltIns).hashCode() + declaration.file.path.hashCode() - return "${fqName}_$hashCode" + val key = declaration.fqNameWhenAvailable.toString() + // counter is used to resolve fqName clashes + val counterValue = jsCodeCounter.getOrPut(key, defaultValue = { 0 }) + jsCodeCounter[key] = counterValue + 1 + val counterSuffix = if (counterValue == 0 && key.lastOrNull()?.isDigit() == false) "" else "_$counterValue" + return "$key$counterSuffix" } override fun visitFunction(declaration: IrFunction) { @@ -79,11 +84,10 @@ class DeclarationGenerator( wasmImportModule } jsCode != null -> { - // TODO: check consistency (currently fails with generated __convertKotlinClosureToJsClosure) // check(declaration.isExternal) { "Non-external fun with @JsFun ${declaration.fqNameWhenAvailable}"} val jsCodeName = jsCodeName(declaration) context.addJsFun(jsCodeName, jsCode) - WasmImportDescriptor("js_code", jsCodeName(declaration)) + WasmImportDescriptor("js_code", jsCodeName) } else -> { null diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ComplexExternalDeclarationsToTopLevelFunctionsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ComplexExternalDeclarationsToTopLevelFunctionsLowering.kt index a409831e3bb..1df314bd59a 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ComplexExternalDeclarationsToTopLevelFunctionsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ComplexExternalDeclarationsToTopLevelFunctionsLowering.kt @@ -201,6 +201,10 @@ class ComplexExternalDeclarationsToTopLevelFunctionsLowering(val context: WasmBa return } + if (function.isFakeOverride) { + return + } + val jsFunctionReference = when { jsFun != null -> "($jsFun)" function.isTopLevelDeclaration -> referenceTopLevelExternalDeclaration(function) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt index 6e13cd6781c..cb35e226d24 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.DeclarationTransformer import org.jetbrains.kotlin.backend.common.ir.addDispatchReceiver import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.serialization.cityHash64 import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.ir2wasm.isBuiltInWasmRefType import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExported @@ -621,7 +622,8 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT } val hashString: String = - functionType.hashCode().absoluteValue.toString(Character.MAX_RADIX) + // Rendering type to improve hash stability across compiler runs + functionType.render().cityHash64().toULong().toString(Character.MAX_RADIX) val originalParameterTypes: List = functionType.arguments.dropLast(1).map { (it as IrTypeProjection).type } diff --git a/js/js.translator/testData/box/native/nestedElements.kt b/js/js.translator/testData/box/native/nestedElements.kt index b3a283e8bb7..1810fa9c0d4 100644 --- a/js/js.translator/testData/box/native/nestedElements.kt +++ b/js/js.translator/testData/box/native/nestedElements.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: WASM // EXPECTED_REACHABLE_NODES: 1310 package foo