[JS IR] Check all signatures of dependent file in IC graph

It is important to check all signatures, because signatures
 can be simultaneously moved between files and modified.
This commit is contained in:
Alexander Korepanov
2022-12-09 16:22:59 +01:00
committed by Space Team
parent 04fcf25ae0
commit 4136189114
12 changed files with 75 additions and 7 deletions
@@ -390,17 +390,44 @@ class CacheUpdater(
val dependentSrcMetadata = dependentCache.fetchSourceFileFullMetadata(dependentSrcFile)
val dependentSignatures = dependentSrcMetadata.directDependencies[libFile, srcFile] ?: emptyMap()
when {
// ignore if the dependent file is already dirty
dependentSrcMetadata is DirtyFileMetadata -> continue
this[dependentLibFile, dependentSrcFile]?.importedSignaturesModified == true -> continue
// ignore if the dependent file imports have been modified, the metadata for it will be rebuilt later
this[dependentLibFile, dependentSrcFile]?.importedSignaturesState == ImportedSignaturesState.MODIFIED -> continue
// update metadata if the direct dependencies have been modified
dependentSignatures.any { signatureHashCalculator[it.key] != it.value } -> {
val newMetadata = addNewMetadata(dependentLibFile, dependentSrcFile, dependentSrcMetadata)
newMetadata.importedSignaturesModified = true
newMetadata.importedSignaturesState = ImportedSignaturesState.MODIFIED
}
// update metadata if the signature set of the direct dependencies has been updated
dependentSignatures.keys != newSignatures -> {
val newMetadata = addNewMetadata(dependentLibFile, dependentSrcFile, dependentSrcMetadata)
newMetadata.directDependencies[libFile, srcFile] = newSignatures.associateWithTo(HashMap(newSignatures.size)) {
signatureHashCalculator[it] ?: notFoundIcError("signature $it hash", libFile, srcFile)
if (newMetadata.importedSignaturesState == ImportedSignaturesState.UNKNOWN) {
val isNonModified = dependentSrcMetadata.directDependencies.allFiles { _, _, signatures ->
signatures.all {
val newHash = signatureHashCalculator[it.key]
// a new hash may be not calculated for the non-loaded symbols, it is ok
newHash == null || newHash == it.value
}
}
newMetadata.importedSignaturesState = if (isNonModified) {
ImportedSignaturesState.NON_MODIFIED
} else {
ImportedSignaturesState.MODIFIED
}
}
// if imports have been modified, metadata for the file will be rebuilt later,
// so if the imports haven't been modified, update the metadata manually
if (newMetadata.importedSignaturesState == ImportedSignaturesState.NON_MODIFIED) {
val newDirectDependencies = newSignatures.associateWithTo(HashMap(newSignatures.size)) {
signatureHashCalculator[it] ?: notFoundIcError("signature $it hash", libFile, srcFile)
}
newMetadata.directDependencies[libFile, srcFile] = newDirectDependencies
}
}
}
@@ -434,13 +461,13 @@ class CacheUpdater(
for ((srcFile, srcFileMetadata) in srcFiles) {
val isExportedSignatureUpdated = srcFileMetadata.isExportedSignaturesUpdated()
if (isExportedSignatureUpdated || srcFileMetadata.importedSignaturesModified) {
if (isExportedSignatureUpdated || srcFileMetadata.importedSignaturesState == ImportedSignaturesState.MODIFIED) {
// if exported signatures or imported inline functions were modified - rebuild
filesToRebuild[srcFile] = srcFileMetadata
if (isExportedSignatureUpdated) {
fileStats.addDirtFileStat(srcFile, DirtyFileState.UPDATED_EXPORTS)
}
if (srcFileMetadata.importedSignaturesModified) {
if (srcFileMetadata.importedSignaturesState == ImportedSignaturesState.MODIFIED) {
fileStats.addDirtFileStat(srcFile, DirtyFileState.UPDATED_IMPORTS)
}
} else {
@@ -136,11 +136,13 @@ internal class DirtyFileMetadata(
}
}
internal enum class ImportedSignaturesState { UNKNOWN, MODIFIED, NON_MODIFIED }
internal class UpdatedDependenciesMetadata(oldMetadata: KotlinSourceFileMetadata) : KotlinSourceFileMetadata() {
private val oldInverseDependencies = oldMetadata.inverseDependencies
private val newExportedSignatures: Set<IdSignature> by lazy { inverseDependencies.flatSignatures() }
var importedSignaturesModified = false
var importedSignaturesState = ImportedSignaturesState.UNKNOWN
override val inverseDependencies = oldMetadata.inverseDependencies.toMutable()
override val directDependencies = oldMetadata.directDependencies.toMutable()
@@ -245,6 +245,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
runTest("js/js.translator/testData/incremental/invalidation/mainModuleInvalidation/");
}
@TestMetadata("moveAndModifyInlineFunction")
public void testMoveAndModifyInlineFunction() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/moveAndModifyInlineFunction/");
}
@TestMetadata("moveFilesBetweenModules")
public void testMoveFilesBetweenModules() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/moveFilesBetweenModules/");
@@ -0,0 +1 @@
inline fun inlineFun() = 0
@@ -0,0 +1 @@
inline fun inlineFun() = 1
@@ -0,0 +1,11 @@
STEP 0:
modifications:
U : l1a.0.kt -> l1a.kt
U : l1b.0.kt -> l1b.kt
added file: l1a.kt, l1b.kt, test.kt
STEP 1:
modifications:
U : l1a.1.kt -> l1a.kt
U : l1b.1.kt -> l1b.kt
modified ir: l1a.kt, l1b.kt
updated imports: test.kt
@@ -0,0 +1 @@
fun test() = inlineFun()
@@ -0,0 +1,7 @@
fun box(stepId: Int): String {
val x = test()
if (x != stepId) {
return "Fail: $x != $stepId"
}
return "OK"
}
@@ -0,0 +1,5 @@
STEP 0:
dependencies: lib1
added file: m.kt
STEP 1:
dependencies: lib1
@@ -0,0 +1,8 @@
MODULES: lib1, main
STEP 0:
libs: lib1, main
dirty js: lib1, main
STEP 1:
libs: lib1, main
dirty js: lib1