JS: cache metadata, grouped by package FQN

This commit is contained in:
Anton Bannykh
2019-04-12 20:54:49 +03:00
parent c1f69ca8d6
commit c3170d1908
13 changed files with 214 additions and 45 deletions
@@ -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 {
@@ -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