From 2e48557a0d0d3018245ccb3eaf1578fc189eefe2 Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Mon, 24 Oct 2022 22:54:30 +0200 Subject: [PATCH] [JS IR] Update hashing in IC infrastructure The patch should reduce possible collisions --- .../ir/backend/js/ic/HashCalculatorForIC.kt | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt index 16cf09c1f2e..7f9b5f5cb68 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt @@ -36,7 +36,18 @@ private class HashCalculatorForIC { private val md5 = MessageDigest.getInstance("MD5") fun update(data: ByteArray) = md5.update(data) - fun update(data: String) = md5.update(data.toByteArray()) + + fun update(data: Int) = (0..3).forEach { md5.update((data shr (it * 8)).toByte()) } + + fun update(data: String) { + update(data.length) + update(data.toByteArray()) + } + + inline fun updateForEach(collection: Collection, f: (T) -> Unit) { + update(collection.size) + collection.forEach { f(it) } + } private fun bytesToULong(d: ByteArray, offset: Int): ULong { var hash = 0UL @@ -70,7 +81,7 @@ internal fun File.fileHashForIC(): ICHash { internal fun CompilerConfiguration.configHashForIC() = HashCalculatorForIC().apply { val importantBooleanSettingKeys = listOf(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION) - for (key in importantBooleanSettingKeys) { + updateForEach(importantBooleanSettingKeys) { key -> update(key.toString()) update(getBoolean(key).toString()) } @@ -82,9 +93,9 @@ internal fun IrElement.irElementHashForIC() = HashCalculatorForIC().also { accept( visitor = DumpIrTreeVisitor( out = object : Appendable { - override fun append(csq: CharSequence) = this.apply { it.update(csq.toString()) } + override fun append(csq: CharSequence) = this.apply { it.update(csq.toString().toByteArray()) } override fun append(csq: CharSequence, start: Int, end: Int) = append(csq.subSequence(start, end)) - override fun append(c: Char) = this.apply { it.update(c.toString()) } + override fun append(c: Char) = append(c.toString()) } ), data = "" ) @@ -95,7 +106,7 @@ internal fun IrSymbol.irSymbolHashForIC() = HashCalculatorForIC().also { // symbol rendering prints very little information about type parameters // TODO may be it make sense to update rendering? (owner as? IrTypeParametersContainer)?.let { typeParameters -> - typeParameters.typeParameters.forEach { typeParameter -> + it.updateForEach(typeParameters.typeParameters) { typeParameter -> it.update(typeParameter.symbol.toString()) } } @@ -112,18 +123,24 @@ internal fun KotlinLibrary.fingerprint(fileIndex: Int) = HashCalculatorForIC().a }.finalize() internal fun CrossModuleReferences.crossModuleReferencesHashForIC() = HashCalculatorForIC().apply { - for (importedModule in importedModules) { + update(moduleKind.ordinal) + + updateForEach(importedModules) { importedModule -> update(importedModule.externalName) update(importedModule.internalName.toString()) + update(importedModule.relativeRequirePath ?: "") } - for (exportFrom in transitiveJsExportFrom) { + + updateForEach(transitiveJsExportFrom) { exportFrom -> update(exportFrom.toString()) } - for (tag in exports.keys.sorted()) { + + updateForEach(exports.keys.sorted()) { tag -> update(tag) update(exports[tag]!!) } - for (tag in imports.keys.sorted()) { + + updateForEach(imports.keys.sorted()) { tag -> val import = imports[tag]!! update(tag) update(import.exportedAs)