JS: cache metadata, grouped by package FQN
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental.js
|
||||
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.File
|
||||
|
||||
// byte arrays are used to simplify passing to different classloaders
|
||||
@@ -27,10 +28,14 @@ interface IncrementalDataProvider {
|
||||
val compiledPackageParts: Map<File, TranslationResultValue>
|
||||
|
||||
val metadataVersion: IntArray
|
||||
|
||||
/** gets non-dirty package metadata from previous compilation */
|
||||
val packageMetadata: Map<String, ByteArray>
|
||||
}
|
||||
|
||||
class IncrementalDataProviderImpl(
|
||||
override val headerMetadata: ByteArray,
|
||||
override val compiledPackageParts: Map<File, TranslationResultValue>,
|
||||
override val metadataVersion: IntArray
|
||||
override val metadataVersion: IntArray,
|
||||
override val packageMetadata: Map<String, ByteArray>
|
||||
) : IncrementalDataProvider
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental.js
|
||||
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.security.MessageDigest
|
||||
@@ -39,6 +40,8 @@ interface IncrementalResultsConsumer {
|
||||
* Used in daemon RPC.
|
||||
*/
|
||||
fun processInlineFunctions(functions: Collection<JsInlineFunctionHash>)
|
||||
|
||||
fun processPackageMetadata(packageName: String, metadata: ByteArray)
|
||||
}
|
||||
|
||||
class JsInlineFunctionHash(val sourceFilePath: String, val fqName: String, val inlineFunctionMd5Hash: Long): Serializable
|
||||
@@ -97,6 +100,14 @@ class IncrementalResultsConsumerImpl : IncrementalResultsConsumer {
|
||||
val mapForSource = _deferInlineFuncs.getOrPut(sourceFile) { hashMapOf() }
|
||||
mapForSource[fqName] = FunctionWithSourceInfo(inlineFunction, line, column)
|
||||
}
|
||||
|
||||
private val _packageMetadata = hashMapOf<String, ByteArray>()
|
||||
val packageMetadata: Map<String, ByteArray>
|
||||
get() = _packageMetadata
|
||||
|
||||
override fun processPackageMetadata(packageName: String, metadata: ByteArray) {
|
||||
_packageMetadata[packageName] = metadata
|
||||
}
|
||||
}
|
||||
|
||||
private fun ByteArray.md5(): Long {
|
||||
|
||||
+31
-18
@@ -75,20 +75,8 @@ object KotlinJavascriptSerializationUtil {
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
metadataVersion: JsMetadataVersion
|
||||
): SerializedMetadata {
|
||||
val serializedFragments = HashMap<FqName, ByteArray>()
|
||||
val module = jsDescriptor.data
|
||||
|
||||
for (fqName in getPackagesFqNames(module).sortedBy { it.asString() }) {
|
||||
val fragment = serializeDescriptors(
|
||||
bindingContext, module,
|
||||
module.getPackage(fqName).memberScope.getContributedDescriptors(),
|
||||
fqName, languageVersionSettings, metadataVersion
|
||||
)
|
||||
|
||||
if (!fragment.isEmpty()) {
|
||||
serializedFragments[fqName] = fragment.toByteArray()
|
||||
}
|
||||
}
|
||||
val serializedFragments =
|
||||
emptyMap<FqName, ByteArray>().missingMetadata(bindingContext, jsDescriptor.data, languageVersionSettings, metadataVersion)
|
||||
|
||||
return SerializedMetadata(serializedFragments, jsDescriptor, languageVersionSettings, metadataVersion)
|
||||
}
|
||||
@@ -258,9 +246,6 @@ object KotlinJavascriptSerializationUtil {
|
||||
return filesProto.build()
|
||||
}
|
||||
|
||||
private fun ProtoBuf.PackageFragment.isEmpty(): Boolean =
|
||||
class_Count == 0 && `package`.let { it.functionCount == 0 && it.propertyCount == 0 && it.typeAliasCount == 0 }
|
||||
|
||||
fun serializeHeader(
|
||||
module: ModuleDescriptor, packageFqName: FqName?, languageVersionSettings: LanguageVersionSettings
|
||||
): JsProtoBuf.Header {
|
||||
@@ -293,7 +278,7 @@ object KotlinJavascriptSerializationUtil {
|
||||
return header.build()
|
||||
}
|
||||
|
||||
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
|
||||
fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
|
||||
return mutableSetOf<FqName>().apply {
|
||||
getSubPackagesFqNames(module.getPackage(FqName.ROOT), this)
|
||||
add(FqName.ROOT)
|
||||
@@ -331,6 +316,34 @@ object KotlinJavascriptSerializationUtil {
|
||||
}
|
||||
}
|
||||
|
||||
fun Map<FqName, ByteArray>.missingMetadata(
|
||||
bindingContext: BindingContext,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
metadataVersion: JsMetadataVersion
|
||||
): Map<FqName, ByteArray> {
|
||||
val serializedFragments = HashMap<FqName, ByteArray>()
|
||||
|
||||
for (fqName in KotlinJavascriptSerializationUtil.getPackagesFqNames(moduleDescriptor).sortedBy { it.asString() }) {
|
||||
if (fqName in this) continue
|
||||
|
||||
val fragment = KotlinJavascriptSerializationUtil.serializeDescriptors(
|
||||
bindingContext, moduleDescriptor,
|
||||
moduleDescriptor.getPackage(fqName).memberScope.getContributedDescriptors(),
|
||||
fqName, languageVersionSettings, metadataVersion
|
||||
)
|
||||
|
||||
if (!fragment.isEmpty()) {
|
||||
serializedFragments[fqName] = fragment.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
return serializedFragments
|
||||
}
|
||||
|
||||
private fun ProtoBuf.PackageFragment.isEmpty(): Boolean =
|
||||
class_Count == 0 && `package`.let { it.functionCount == 0 && it.propertyCount == 0 && it.typeAliasCount == 0 }
|
||||
|
||||
data class KotlinJavaScriptLibraryParts(
|
||||
val header: JsProtoBuf.Header,
|
||||
val body: List<ProtoBuf.PackageFragment>,
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.cli.common.output.writeAllTo
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.daemon.common.PackageMetadata
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
|
||||
@@ -48,6 +49,7 @@ import org.jetbrains.kotlin.js.test.interop.ScriptEngineV8Lazy
|
||||
import org.jetbrains.kotlin.js.test.utils.*
|
||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||
import org.jetbrains.kotlin.metadata.DebugProtoBuf
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
@@ -395,6 +397,7 @@ abstract class BasicBoxTest(
|
||||
val sourceFile = File(testFile.fileName)
|
||||
incrementalData.translatedFiles.remove(sourceFile)
|
||||
sourceToTranslationUnit[sourceFile] = TranslationUnit.SourceFile(createPsiFile(testFile.fileName))
|
||||
incrementalData.packageMetadata.remove(testFile.packageName)
|
||||
}
|
||||
}
|
||||
for ((sourceFile, data) in incrementalData.translatedFiles) {
|
||||
@@ -461,7 +464,11 @@ abstract class BasicBoxTest(
|
||||
|
||||
private fun removeRecompiledSuffix(text: String): String = text.replace("-recompiled.js", ".js")
|
||||
|
||||
class IncrementalData(var header: ByteArray? = null, val translatedFiles: MutableMap<File, TranslationResultValue> = hashMapOf())
|
||||
class IncrementalData(
|
||||
var header: ByteArray? = null,
|
||||
val translatedFiles: MutableMap<File, TranslationResultValue> = hashMapOf(),
|
||||
val packageMetadata: MutableMap<String, ByteArray> = hashMapOf()
|
||||
)
|
||||
|
||||
protected open fun translateFiles(
|
||||
units: List<TranslationUnit>,
|
||||
@@ -505,6 +512,8 @@ abstract class BasicBoxTest(
|
||||
incrementalData.translatedFiles[srcFile] = data
|
||||
}
|
||||
|
||||
incrementalData.packageMetadata += incrementalService.packageMetadata
|
||||
|
||||
incrementalData.header = incrementalService.headerMetadata
|
||||
}
|
||||
|
||||
@@ -640,7 +649,7 @@ abstract class BasicBoxTest(
|
||||
if (header != null) {
|
||||
configuration.put(
|
||||
JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER,
|
||||
IncrementalDataProviderImpl(header, incrementalData.translatedFiles, JsMetadataVersion.INSTANCE.toArray())
|
||||
IncrementalDataProviderImpl(header, incrementalData.translatedFiles, JsMetadataVersion.INSTANCE.toArray(), incrementalData.packageMetadata)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -768,7 +777,12 @@ abstract class BasicBoxTest(
|
||||
currentModule.sourceMapSourceEmbedding = SourceMapSourceEmbedding.valueOf(match.groupValues[1])
|
||||
}
|
||||
|
||||
return TestFile(temporaryFile.absolutePath, currentModule, recompile = RECOMPILE_PATTERN.matcher(text).find())
|
||||
return TestFile(
|
||||
temporaryFile.absolutePath,
|
||||
currentModule,
|
||||
recompile = RECOMPILE_PATTERN.matcher(text).find(),
|
||||
packageName = ktFile.packageFqName.asString()
|
||||
)
|
||||
}
|
||||
|
||||
override fun createModule(name: String, dependencies: List<String>, friends: List<String>) =
|
||||
@@ -779,7 +793,7 @@ abstract class BasicBoxTest(
|
||||
}
|
||||
}
|
||||
|
||||
private class TestFile(val fileName: String, val module: TestModule, val recompile: Boolean) {
|
||||
private class TestFile(val fileName: String, val module: TestModule, val recompile: Boolean, val packageName: String) {
|
||||
init {
|
||||
module.files += this
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.js.missingMetadata
|
||||
|
||||
/**
|
||||
* An entry point of translator.
|
||||
@@ -140,8 +141,8 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
expandIsCalls(translationResult.newFragments)
|
||||
checkCanceled()
|
||||
|
||||
updatePackageMetadata(translationResult, bindingTrace, moduleDescriptor, packageMetadata)
|
||||
trySaveIncrementalData(translationResult, pathResolver, bindingTrace, moduleDescriptor, packageMetadata)
|
||||
updateMetadataMap(bindingTrace.bindingContext, moduleDescriptor, packageMetadata)
|
||||
trySaveIncrementalData(translationResult, pathResolver, bindingTrace, moduleDescriptor)
|
||||
checkCanceled()
|
||||
|
||||
// Global phases
|
||||
@@ -167,11 +168,34 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMetadataMap(
|
||||
bindingContext: BindingContext,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
packageMetadata: MutableMap<FqName, ByteArray>
|
||||
) {
|
||||
val additionalMetadata = packageMetadata.missingMetadata(
|
||||
bindingContext,
|
||||
moduleDescriptor,
|
||||
config.configuration.languageVersionSettings,
|
||||
config.configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsMetadataVersion ?: JsMetadataVersion.INSTANCE)
|
||||
|
||||
for ((packageName, metadata) in additionalMetadata) {
|
||||
incrementalResults?.processPackageMetadata(packageName.asString(), metadata)
|
||||
}
|
||||
|
||||
packageMetadata += additionalMetadata
|
||||
}
|
||||
|
||||
private fun checkCanceled() {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
}
|
||||
|
||||
private fun serializeScope(bindingContext: BindingContext, moduleDescriptor: ModuleDescriptor, packageName: FqName, scope: Collection<DeclarationDescriptor>): ProtoBuf.PackageFragment {
|
||||
private fun serializeScope(
|
||||
bindingContext: BindingContext,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
packageName: FqName,
|
||||
scope: Collection<DeclarationDescriptor>
|
||||
): ProtoBuf.PackageFragment {
|
||||
val metadataVersion = config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)
|
||||
return KotlinJavascriptSerializationUtil.serializeDescriptors(
|
||||
bindingContext,
|
||||
@@ -183,25 +207,11 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun updatePackageMetadata(
|
||||
translationResult: AstGenerationResult,
|
||||
bindingTrace: BindingTrace,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
packageMetadata: MutableMap<FqName, ByteArray>
|
||||
) {
|
||||
translationResult.translatedSourceFiles.keys.mapTo(mutableSetOf()) { it.file.packageFqName }.forEach { packageName ->
|
||||
val memberScope = moduleDescriptor.getPackage(packageName).memberScope.getContributedDescriptors()
|
||||
val bytes = serializeScope(bindingTrace.bindingContext, moduleDescriptor, packageName, memberScope).toByteArray()
|
||||
packageMetadata[packageName] = bytes
|
||||
}
|
||||
}
|
||||
|
||||
private fun trySaveIncrementalData(
|
||||
translationResult: AstGenerationResult,
|
||||
pathResolver: SourceFilePathResolver,
|
||||
bindingTrace: BindingTrace,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
packageMetadata: Map<FqName, ByteArray>
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
) {
|
||||
// TODO Maybe switch validation on for recompile
|
||||
if (incrementalResults == null && !shouldValidateJsAst) return
|
||||
|
||||
Reference in New Issue
Block a user