JS: cache metadata, grouped by package FQN
This commit is contained in:
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.metadata.js.JsProtoBuf
|
|||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.name.parentOrNull
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
|
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
|
||||||
import java.io.DataInput
|
import java.io.DataInput
|
||||||
@@ -41,6 +42,7 @@ open class IncrementalJsCache(
|
|||||||
private const val TRANSLATION_RESULT_MAP = "translation-result"
|
private const val TRANSLATION_RESULT_MAP = "translation-result"
|
||||||
private const val INLINE_FUNCTIONS = "inline-functions"
|
private const val INLINE_FUNCTIONS = "inline-functions"
|
||||||
private const val HEADER_FILE_NAME = "header.meta"
|
private const val HEADER_FILE_NAME = "header.meta"
|
||||||
|
private const val PACKAGE_META_FILE = "packages-meta"
|
||||||
|
|
||||||
fun hasHeaderFile(cachesDir: File) = File(cachesDir, HEADER_FILE_NAME).exists()
|
fun hasHeaderFile(cachesDir: File) = File(cachesDir, HEADER_FILE_NAME).exists()
|
||||||
}
|
}
|
||||||
@@ -49,8 +51,10 @@ open class IncrementalJsCache(
|
|||||||
override val dirtyOutputClassesMap = registerMap(DirtyClassesFqNameMap(DIRTY_OUTPUT_CLASSES.storageFile))
|
override val dirtyOutputClassesMap = registerMap(DirtyClassesFqNameMap(DIRTY_OUTPUT_CLASSES.storageFile))
|
||||||
private val translationResults = registerMap(TranslationResultMap(TRANSLATION_RESULT_MAP.storageFile, pathConverter))
|
private val translationResults = registerMap(TranslationResultMap(TRANSLATION_RESULT_MAP.storageFile, pathConverter))
|
||||||
private val inlineFunctions = registerMap(InlineFunctionsMap(INLINE_FUNCTIONS.storageFile, pathConverter))
|
private val inlineFunctions = registerMap(InlineFunctionsMap(INLINE_FUNCTIONS.storageFile, pathConverter))
|
||||||
|
private val packageMetadata = registerMap(PackageMetadataMap(PACKAGE_META_FILE.storageFile))
|
||||||
|
|
||||||
private val dirtySources = hashSetOf<File>()
|
private val dirtySources = hashSetOf<File>()
|
||||||
|
private val dirtyPackages = hashSetOf<String>()
|
||||||
|
|
||||||
private val headerFile: File
|
private val headerFile: File
|
||||||
get() = File(cachesDir, HEADER_FILE_NAME)
|
get() = File(cachesDir, HEADER_FILE_NAME)
|
||||||
@@ -63,6 +67,11 @@ open class IncrementalJsCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun markDirty(removedAndCompiledSources: Collection<File>) {
|
override fun markDirty(removedAndCompiledSources: Collection<File>) {
|
||||||
|
removedAndCompiledSources.forEach { sourceFile ->
|
||||||
|
sourceToClassesMap[sourceFile].forEach {
|
||||||
|
dirtyPackages += it.parentOrNull()?.asString() ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
super.markDirty(removedAndCompiledSources)
|
super.markDirty(removedAndCompiledSources)
|
||||||
dirtySources.addAll(removedAndCompiledSources)
|
dirtySources.addAll(removedAndCompiledSources)
|
||||||
}
|
}
|
||||||
@@ -95,6 +104,11 @@ open class IncrementalJsCache(
|
|||||||
for ((srcFile, inlineDeclarations) in incrementalResults.inlineFunctions) {
|
for ((srcFile, inlineDeclarations) in incrementalResults.inlineFunctions) {
|
||||||
inlineFunctions.process(srcFile, inlineDeclarations, changesCollector)
|
inlineFunctions.process(srcFile, inlineDeclarations, changesCollector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ((packageName, metadata) in incrementalResults.packageMetadata) {
|
||||||
|
packageMetadata.put(packageName, metadata)
|
||||||
|
dirtyPackages.remove(packageName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerOutputForFile(srcFile: File, name: FqName) {
|
private fun registerOutputForFile(srcFile: File, name: FqName) {
|
||||||
@@ -108,18 +122,31 @@ open class IncrementalJsCache(
|
|||||||
inlineFunctions.remove(it)
|
inlineFunctions.remove(it)
|
||||||
}
|
}
|
||||||
removeAllFromClassStorage(dirtyOutputClassesMap.getDirtyOutputClasses(), changesCollector)
|
removeAllFromClassStorage(dirtyOutputClassesMap.getDirtyOutputClasses(), changesCollector)
|
||||||
|
dirtyPackages.forEach {
|
||||||
|
packageMetadata.remove(it)
|
||||||
|
}
|
||||||
dirtySources.clear()
|
dirtySources.clear()
|
||||||
dirtyOutputClassesMap.clean()
|
dirtyOutputClassesMap.clean()
|
||||||
|
dirtyPackages.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nonDirtyPackageParts(): Map<File, TranslationResultValue> =
|
fun nonDirtyPackageParts(): Map<File, TranslationResultValue> =
|
||||||
hashMapOf<File, TranslationResultValue>().apply {
|
hashMapOf<File, TranslationResultValue>().apply {
|
||||||
for (file in translationResults.keys()) {
|
for (file in translationResults.keys()) {
|
||||||
|
|
||||||
if (file !in dirtySources) {
|
if (file !in dirtySources) {
|
||||||
put(file, translationResults[file]!!)
|
put(file, translationResults[file]!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun packageMetadata(): Map<String, ByteArray> = hashMapOf<String, ByteArray>().apply {
|
||||||
|
for (fqNameString in packageMetadata.keys()) {
|
||||||
|
if (fqNameString !in dirtyPackages) {
|
||||||
|
put(fqNameString, packageMetadata[fqNameString]!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object TranslationResultValueExternalizer : DataExternalizer<TranslationResultValue> {
|
private object TranslationResultValueExternalizer : DataExternalizer<TranslationResultValue> {
|
||||||
@@ -154,7 +181,8 @@ private object TranslationResultValueExternalizer : DataExternalizer<Translation
|
|||||||
private class TranslationResultMap(
|
private class TranslationResultMap(
|
||||||
storageFile: File,
|
storageFile: File,
|
||||||
private val pathConverter: FileToPathConverter
|
private val pathConverter: FileToPathConverter
|
||||||
) : BasicStringMap<TranslationResultValue>(storageFile, TranslationResultValueExternalizer) {
|
) :
|
||||||
|
BasicStringMap<TranslationResultValue>(storageFile, TranslationResultValueExternalizer) {
|
||||||
override fun dumpValue(value: TranslationResultValue): String =
|
override fun dumpValue(value: TranslationResultValue): String =
|
||||||
"Metadata: ${value.metadata.md5()}, Binary AST: ${value.binaryAst.md5()}, InlineData: ${value.inlineData.md5()}"
|
"Metadata: ${value.metadata.md5()}, Binary AST: ${value.binaryAst.md5()}, InlineData: ${value.inlineData.md5()}"
|
||||||
|
|
||||||
@@ -181,7 +209,7 @@ private class TranslationResultMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getProtoData(sourceFile: File, metadata: ByteArray): Map<ClassId, ProtoData> {
|
fun getProtoData(sourceFile: File, metadata: ByteArray): Map<ClassId, ProtoData> {
|
||||||
val classes = hashMapOf<ClassId, ProtoData>()
|
val classes = hashMapOf<ClassId, ProtoData>()
|
||||||
val proto = ProtoBuf.PackageFragment.parseFrom(metadata, JsSerializerProtocol.extensionRegistry)
|
val proto = ProtoBuf.PackageFragment.parseFrom(metadata, JsSerializerProtocol.extensionRegistry)
|
||||||
val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
|
val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
|
||||||
@@ -227,4 +255,35 @@ private class InlineFunctionsMap(
|
|||||||
|
|
||||||
override fun dumpValue(value: Map<String, Long>): String =
|
override fun dumpValue(value: Map<String, Long>): String =
|
||||||
value.dumpMap { java.lang.Long.toHexString(it) }
|
value.dumpMap { java.lang.Long.toHexString(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ByteArrayExternalizer : DataExternalizer<ByteArray> {
|
||||||
|
override fun save(output: DataOutput, value: ByteArray) {
|
||||||
|
output.writeInt(value.size)
|
||||||
|
output.write(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(input: DataInput): ByteArray {
|
||||||
|
val size = input.readInt()
|
||||||
|
val array = ByteArray(size)
|
||||||
|
input.readFully(array)
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class PackageMetadataMap(storageFile: File) : BasicStringMap<ByteArray>(storageFile, ByteArrayExternalizer) {
|
||||||
|
fun put(packageName: String, newMetadata: ByteArray) {
|
||||||
|
storage[packageName] = newMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remove(packageName: String) {
|
||||||
|
storage.remove(packageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun keys() = storage.keys
|
||||||
|
|
||||||
|
operator fun get(packageName: String) = storage[packageName]
|
||||||
|
|
||||||
|
override fun dumpValue(value: ByteArray): String = "Package metadata: ${value.md5()}"
|
||||||
}
|
}
|
||||||
+3
@@ -18,4 +18,7 @@ class IncrementalDataProviderFromCache(private val cache: IncrementalJsCache) :
|
|||||||
|
|
||||||
override val metadataVersion: IntArray
|
override val metadataVersion: IntArray
|
||||||
get() = JsMetadataVersion.INSTANCE.toArray() // TODO: store and load correct metadata version
|
get() = JsMetadataVersion.INSTANCE.toArray() // TODO: store and load correct metadata version
|
||||||
|
|
||||||
|
override val packageMetadata: Map<String, ByteArray>
|
||||||
|
get() = cache.packageMetadata()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import org.jetbrains.kotlin.js.facade.TranslationUnit;
|
|||||||
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion;
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion;
|
||||||
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
||||||
@@ -73,6 +74,7 @@ import org.jetbrains.kotlin.utils.*;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR;
|
import static org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR;
|
||||||
import static org.jetbrains.kotlin.cli.common.ExitCode.OK;
|
import static org.jetbrains.kotlin.cli.common.ExitCode.OK;
|
||||||
@@ -144,6 +146,15 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
|
|||||||
}
|
}
|
||||||
Arrays.sort(allSources);
|
Arrays.sort(allSources);
|
||||||
|
|
||||||
|
Set<FqName> dirtyPackages = nonCompiledSources.values().stream().map(KtFile::getPackageFqName).collect(Collectors.toSet());
|
||||||
|
Map<FqName, byte[]> packageMetadata = new HashMap<>();
|
||||||
|
for (Map.Entry<String, byte[]> e : incrementalDataProvider.getPackageMetadata().entrySet()) {
|
||||||
|
FqName name = new FqName(e.getKey());
|
||||||
|
if (!dirtyPackages.contains(name)) {
|
||||||
|
packageMetadata.put(name, e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<TranslationUnit> translationUnits = new ArrayList<>();
|
List<TranslationUnit> translationUnits = new ArrayList<>();
|
||||||
for (i = 0; i < allSources.length; i++) {
|
for (i = 0; i < allSources.length; i++) {
|
||||||
KtFile nonCompiled = nonCompiledSources.get(allSources[i]);
|
KtFile nonCompiled = nonCompiledSources.get(allSources[i]);
|
||||||
@@ -155,7 +166,7 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
|
|||||||
translationUnits.add(new TranslationUnit.BinaryAst(translatedValue.getBinaryAst(), translatedValue.getInlineData()));
|
translationUnits.add(new TranslationUnit.BinaryAst(translatedValue.getBinaryAst(), translatedValue.getInlineData()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return translator.translateUnits(reporter, translationUnits, mainCallParameters, jsAnalysisResult);
|
return translator.translateUnits(reporter, translationUnits, mainCallParameters, jsAnalysisResult, packageMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionsKt.sortBy(allKotlinFiles, ktFile -> VfsUtilCore.virtualToIoFile(ktFile.getVirtualFile()));
|
CollectionsKt.sortBy(allKotlinFiles, ktFile -> VfsUtilCore.virtualToIoFile(ktFile.getVirtualFile()));
|
||||||
|
|||||||
+9
@@ -134,6 +134,10 @@ open class CompilerCallbackServicesFacadeServer(
|
|||||||
incrementalResultsConsumer!!.processInlineFunctions(functions)
|
incrementalResultsConsumer!!.processInlineFunctions(functions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun incrementalResultsConsumer_processPackageMetadata(packageName: String, metadata: ByteArray) {
|
||||||
|
incrementalResultsConsumer!!.processPackageMetadata(packageName, metadata)
|
||||||
|
}
|
||||||
|
|
||||||
override fun incrementalDataProvider_getHeaderMetadata(): ByteArray = incrementalDataProvider!!.headerMetadata
|
override fun incrementalDataProvider_getHeaderMetadata(): ByteArray = incrementalDataProvider!!.headerMetadata
|
||||||
|
|
||||||
override fun incrementalDataProvider_getMetadataVersion(): IntArray = incrementalDataProvider!!.metadataVersion
|
override fun incrementalDataProvider_getMetadataVersion(): IntArray = incrementalDataProvider!!.metadataVersion
|
||||||
@@ -142,4 +146,9 @@ open class CompilerCallbackServicesFacadeServer(
|
|||||||
incrementalDataProvider!!.compiledPackageParts.entries.map {
|
incrementalDataProvider!!.compiledPackageParts.entries.map {
|
||||||
CompiledPackagePart(it.key.path, it.value.metadata, it.value.binaryAst, it.value.inlineData)
|
CompiledPackagePart(it.key.path, it.value.metadata, it.value.binaryAst, it.value.inlineData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun incrementalDataProvider_getPackageMetadata(): Collection<PackageMetadata> =
|
||||||
|
incrementalDataProvider!!.packageMetadata.entries.map { (fqName, metadata) ->
|
||||||
|
PackageMetadata(fqName, metadata)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -112,6 +112,9 @@ interface CompilerCallbackServicesFacade : Remote {
|
|||||||
@Throws(RemoteException::class)
|
@Throws(RemoteException::class)
|
||||||
fun incrementalResultsConsumer_processInlineFunctions(functions: Collection<JsInlineFunctionHash>)
|
fun incrementalResultsConsumer_processInlineFunctions(functions: Collection<JsInlineFunctionHash>)
|
||||||
|
|
||||||
|
@Throws(RemoteException::class)
|
||||||
|
fun incrementalResultsConsumer_processPackageMetadata(packageName: String, metadata: ByteArray)
|
||||||
|
|
||||||
// ---------------------------------------------------
|
// ---------------------------------------------------
|
||||||
// IncrementalDataProvider (js)
|
// IncrementalDataProvider (js)
|
||||||
@Throws(RemoteException::class)
|
@Throws(RemoteException::class)
|
||||||
@@ -122,6 +125,9 @@ interface CompilerCallbackServicesFacade : Remote {
|
|||||||
|
|
||||||
@Throws(RemoteException::class)
|
@Throws(RemoteException::class)
|
||||||
fun incrementalDataProvider_getMetadataVersion(): IntArray
|
fun incrementalDataProvider_getMetadataVersion(): IntArray
|
||||||
|
|
||||||
|
@Throws(RemoteException::class)
|
||||||
|
fun incrementalDataProvider_getPackageMetadata(): Collection<PackageMetadata>
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompiledPackagePart(
|
class CompiledPackagePart(
|
||||||
@@ -129,6 +135,17 @@ class CompiledPackagePart(
|
|||||||
val metadata: ByteArray, val binaryAst: ByteArray, val inlineData: ByteArray
|
val metadata: ByteArray, val binaryAst: ByteArray, val inlineData: ByteArray
|
||||||
) : Serializable
|
) : Serializable
|
||||||
|
|
||||||
|
class PackageMetadata(
|
||||||
|
val packageName: String,
|
||||||
|
val metadata: ByteArray
|
||||||
|
) : Serializable {
|
||||||
|
companion object {
|
||||||
|
// just a random number, but should never be changed to avoid deserialization problems
|
||||||
|
private val serialVersionUID: Long = 54021986502349756L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class RmiFriendlyCompilationCanceledException : Exception(), Serializable {
|
class RmiFriendlyCompilationCanceledException : Exception(), Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
// just a random number, but should never be changed to avoid deserialization problems
|
// just a random number, but should never be changed to avoid deserialization problems
|
||||||
|
|||||||
@@ -33,4 +33,14 @@ class RemoteIncrementalDataProvider(val facade: CompilerCallbackServicesFacade,
|
|||||||
get() = rpcProfiler.withMeasure(this) {
|
get() = rpcProfiler.withMeasure(this) {
|
||||||
facade.incrementalDataProvider_getMetadataVersion()
|
facade.incrementalDataProvider_getMetadataVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val packageMetadata: Map<String, ByteArray>
|
||||||
|
get() = rpcProfiler.withMeasure(this) {
|
||||||
|
val result = mutableMapOf<String, ByteArray>()
|
||||||
|
facade.incrementalDataProvider_getPackageMetadata().forEach {
|
||||||
|
val prev = result.put(it.packageName, it.metadata)
|
||||||
|
check(prev == null) { "packageMetadata: duplicated entry for package `${it.packageName}`" }
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.io.File
|
|||||||
|
|
||||||
class RemoteIncrementalResultsConsumer(val facade: CompilerCallbackServicesFacade, eventManager: EventManager, val rpcProfiler: Profiler) :
|
class RemoteIncrementalResultsConsumer(val facade: CompilerCallbackServicesFacade, eventManager: EventManager, val rpcProfiler: Profiler) :
|
||||||
IncrementalResultsConsumer {
|
IncrementalResultsConsumer {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
eventManager.
|
eventManager.
|
||||||
onCompilationFinished(this::flush)
|
onCompilationFinished(this::flush)
|
||||||
@@ -42,6 +43,12 @@ class RemoteIncrementalResultsConsumer(val facade: CompilerCallbackServicesFacad
|
|||||||
|
|
||||||
override fun processInlineFunctions(functions: Collection<JsInlineFunctionHash>) = error("Should not be called in Daemon Server")
|
override fun processInlineFunctions(functions: Collection<JsInlineFunctionHash>) = error("Should not be called in Daemon Server")
|
||||||
|
|
||||||
|
override fun processPackageMetadata(packageName: String, metadata: ByteArray) {
|
||||||
|
rpcProfiler.withMeasure(this) {
|
||||||
|
facade.incrementalResultsConsumer_processPackageMetadata(packageName, metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun flush() {
|
fun flush() {
|
||||||
rpcProfiler.withMeasure(this) {
|
rpcProfiler.withMeasure(this) {
|
||||||
facade.incrementalResultsConsumer_processInlineFunctions(deferInlineFuncs.map {
|
facade.incrementalResultsConsumer_processInlineFunctions(deferInlineFuncs.map {
|
||||||
|
|||||||
+1
-1
@@ -123,7 +123,7 @@ abstract class AbstractJsLookupTrackerTest : AbstractLookupTrackerTest() {
|
|||||||
if (header != null) {
|
if (header != null) {
|
||||||
register(
|
register(
|
||||||
IncrementalDataProvider::class.java,
|
IncrementalDataProvider::class.java,
|
||||||
IncrementalDataProviderImpl(header!!, packageParts, JsMetadataVersion.INSTANCE.toArray())
|
IncrementalDataProviderImpl(header!!, packageParts, JsMetadataVersion.INSTANCE.toArray(), emptyMap()) // TODO pass correct metadata
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.js
|
package org.jetbrains.kotlin.incremental.js
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
// byte arrays are used to simplify passing to different classloaders
|
// byte arrays are used to simplify passing to different classloaders
|
||||||
@@ -27,10 +28,14 @@ interface IncrementalDataProvider {
|
|||||||
val compiledPackageParts: Map<File, TranslationResultValue>
|
val compiledPackageParts: Map<File, TranslationResultValue>
|
||||||
|
|
||||||
val metadataVersion: IntArray
|
val metadataVersion: IntArray
|
||||||
|
|
||||||
|
/** gets non-dirty package metadata from previous compilation */
|
||||||
|
val packageMetadata: Map<String, ByteArray>
|
||||||
}
|
}
|
||||||
|
|
||||||
class IncrementalDataProviderImpl(
|
class IncrementalDataProviderImpl(
|
||||||
override val headerMetadata: ByteArray,
|
override val headerMetadata: ByteArray,
|
||||||
override val compiledPackageParts: Map<File, TranslationResultValue>,
|
override val compiledPackageParts: Map<File, TranslationResultValue>,
|
||||||
override val metadataVersion: IntArray
|
override val metadataVersion: IntArray,
|
||||||
|
override val packageMetadata: Map<String, ByteArray>
|
||||||
) : IncrementalDataProvider
|
) : IncrementalDataProvider
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental.js
|
package org.jetbrains.kotlin.incremental.js
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
@@ -39,6 +40,8 @@ interface IncrementalResultsConsumer {
|
|||||||
* Used in daemon RPC.
|
* Used in daemon RPC.
|
||||||
*/
|
*/
|
||||||
fun processInlineFunctions(functions: Collection<JsInlineFunctionHash>)
|
fun processInlineFunctions(functions: Collection<JsInlineFunctionHash>)
|
||||||
|
|
||||||
|
fun processPackageMetadata(packageName: String, metadata: ByteArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
class JsInlineFunctionHash(val sourceFilePath: String, val fqName: String, val inlineFunctionMd5Hash: Long): Serializable
|
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() }
|
val mapForSource = _deferInlineFuncs.getOrPut(sourceFile) { hashMapOf() }
|
||||||
mapForSource[fqName] = FunctionWithSourceInfo(inlineFunction, line, column)
|
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 {
|
private fun ByteArray.md5(): Long {
|
||||||
|
|||||||
+31
-18
@@ -75,20 +75,8 @@ object KotlinJavascriptSerializationUtil {
|
|||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
metadataVersion: JsMetadataVersion
|
metadataVersion: JsMetadataVersion
|
||||||
): SerializedMetadata {
|
): SerializedMetadata {
|
||||||
val serializedFragments = HashMap<FqName, ByteArray>()
|
val serializedFragments =
|
||||||
val module = jsDescriptor.data
|
emptyMap<FqName, ByteArray>().missingMetadata(bindingContext, jsDescriptor.data, languageVersionSettings, metadataVersion)
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SerializedMetadata(serializedFragments, jsDescriptor, languageVersionSettings, metadataVersion)
|
return SerializedMetadata(serializedFragments, jsDescriptor, languageVersionSettings, metadataVersion)
|
||||||
}
|
}
|
||||||
@@ -258,9 +246,6 @@ object KotlinJavascriptSerializationUtil {
|
|||||||
return filesProto.build()
|
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(
|
fun serializeHeader(
|
||||||
module: ModuleDescriptor, packageFqName: FqName?, languageVersionSettings: LanguageVersionSettings
|
module: ModuleDescriptor, packageFqName: FqName?, languageVersionSettings: LanguageVersionSettings
|
||||||
): JsProtoBuf.Header {
|
): JsProtoBuf.Header {
|
||||||
@@ -293,7 +278,7 @@ object KotlinJavascriptSerializationUtil {
|
|||||||
return header.build()
|
return header.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
|
fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
|
||||||
return mutableSetOf<FqName>().apply {
|
return mutableSetOf<FqName>().apply {
|
||||||
getSubPackagesFqNames(module.getPackage(FqName.ROOT), this)
|
getSubPackagesFqNames(module.getPackage(FqName.ROOT), this)
|
||||||
add(FqName.ROOT)
|
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(
|
data class KotlinJavaScriptLibraryParts(
|
||||||
val header: JsProtoBuf.Header,
|
val header: JsProtoBuf.Header,
|
||||||
val body: List<ProtoBuf.PackageFragment>,
|
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.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.config.*
|
import org.jetbrains.kotlin.config.*
|
||||||
|
import org.jetbrains.kotlin.daemon.common.PackageMetadata
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
|
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
|
||||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
|
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.test.utils.*
|
||||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||||
import org.jetbrains.kotlin.metadata.DebugProtoBuf
|
import org.jetbrains.kotlin.metadata.DebugProtoBuf
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
@@ -395,6 +397,7 @@ abstract class BasicBoxTest(
|
|||||||
val sourceFile = File(testFile.fileName)
|
val sourceFile = File(testFile.fileName)
|
||||||
incrementalData.translatedFiles.remove(sourceFile)
|
incrementalData.translatedFiles.remove(sourceFile)
|
||||||
sourceToTranslationUnit[sourceFile] = TranslationUnit.SourceFile(createPsiFile(testFile.fileName))
|
sourceToTranslationUnit[sourceFile] = TranslationUnit.SourceFile(createPsiFile(testFile.fileName))
|
||||||
|
incrementalData.packageMetadata.remove(testFile.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ((sourceFile, data) in incrementalData.translatedFiles) {
|
for ((sourceFile, data) in incrementalData.translatedFiles) {
|
||||||
@@ -461,7 +464,11 @@ abstract class BasicBoxTest(
|
|||||||
|
|
||||||
private fun removeRecompiledSuffix(text: String): String = text.replace("-recompiled.js", ".js")
|
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(
|
protected open fun translateFiles(
|
||||||
units: List<TranslationUnit>,
|
units: List<TranslationUnit>,
|
||||||
@@ -505,6 +512,8 @@ abstract class BasicBoxTest(
|
|||||||
incrementalData.translatedFiles[srcFile] = data
|
incrementalData.translatedFiles[srcFile] = data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incrementalData.packageMetadata += incrementalService.packageMetadata
|
||||||
|
|
||||||
incrementalData.header = incrementalService.headerMetadata
|
incrementalData.header = incrementalService.headerMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +649,7 @@ abstract class BasicBoxTest(
|
|||||||
if (header != null) {
|
if (header != null) {
|
||||||
configuration.put(
|
configuration.put(
|
||||||
JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER,
|
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])
|
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>) =
|
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 {
|
init {
|
||||||
module.files += this
|
module.files += this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf
|
||||||
|
import org.jetbrains.kotlin.serialization.js.missingMetadata
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An entry point of translator.
|
* An entry point of translator.
|
||||||
@@ -140,8 +141,8 @@ class K2JSTranslator @JvmOverloads constructor(
|
|||||||
expandIsCalls(translationResult.newFragments)
|
expandIsCalls(translationResult.newFragments)
|
||||||
checkCanceled()
|
checkCanceled()
|
||||||
|
|
||||||
updatePackageMetadata(translationResult, bindingTrace, moduleDescriptor, packageMetadata)
|
updateMetadataMap(bindingTrace.bindingContext, moduleDescriptor, packageMetadata)
|
||||||
trySaveIncrementalData(translationResult, pathResolver, bindingTrace, moduleDescriptor, packageMetadata)
|
trySaveIncrementalData(translationResult, pathResolver, bindingTrace, moduleDescriptor)
|
||||||
checkCanceled()
|
checkCanceled()
|
||||||
|
|
||||||
// Global phases
|
// 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() {
|
private fun checkCanceled() {
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.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)
|
val metadataVersion = config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)
|
||||||
return KotlinJavascriptSerializationUtil.serializeDescriptors(
|
return KotlinJavascriptSerializationUtil.serializeDescriptors(
|
||||||
bindingContext,
|
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(
|
private fun trySaveIncrementalData(
|
||||||
translationResult: AstGenerationResult,
|
translationResult: AstGenerationResult,
|
||||||
pathResolver: SourceFilePathResolver,
|
pathResolver: SourceFilePathResolver,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor
|
||||||
packageMetadata: Map<FqName, ByteArray>
|
|
||||||
) {
|
) {
|
||||||
// TODO Maybe switch validation on for recompile
|
// TODO Maybe switch validation on for recompile
|
||||||
if (incrementalResults == null && !shouldValidateJsAst) return
|
if (incrementalResults == null && !shouldValidateJsAst) return
|
||||||
|
|||||||
Reference in New Issue
Block a user