JS: don't load binary AST unless required by the inliner
This commit is contained in:
@@ -47,7 +47,9 @@ import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsProgramFragment
|
||||
import org.jetbrains.kotlin.js.coroutine.transformCoroutines
|
||||
import org.jetbrains.kotlin.js.translate.general.AstGenerationResult
|
||||
import org.jetbrains.kotlin.metadata.js.JsProtoBuf
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf
|
||||
|
||||
/**
|
||||
* An entry point of translator.
|
||||
@@ -129,7 +131,7 @@ class K2JSTranslator(private val config: JsConfig) {
|
||||
expandIsCalls(translationResult.newFragments)
|
||||
checkCanceled()
|
||||
|
||||
trySaveIncrementalData(files, translationResult, pathResolver, bindingTrace, moduleDescriptor)
|
||||
trySaveIncrementalData(translationResult, pathResolver, bindingTrace, moduleDescriptor)
|
||||
checkCanceled()
|
||||
|
||||
// Global phases
|
||||
@@ -159,7 +161,6 @@ class K2JSTranslator(private val config: JsConfig) {
|
||||
}
|
||||
|
||||
private fun trySaveIncrementalData(
|
||||
files: List<KtFile>,
|
||||
translationResult: AstGenerationResult,
|
||||
pathResolver: SourceFilePathResolver,
|
||||
bindingTrace: BindingTrace,
|
||||
@@ -175,13 +176,14 @@ class K2JSTranslator(private val config: JsConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
for (file in files) {
|
||||
val fragment = translationResult.fragmentMap[file] ?: error("Could not find AST for file: $file")
|
||||
for ((sourceUnit, fileTranslationResult) in translationResult.translatedSourceFiles) {
|
||||
val file = sourceUnit.file
|
||||
val fragment = fileTranslationResult.fragment
|
||||
val output = ByteArrayOutputStream()
|
||||
serializer.serialize(fragment, output)
|
||||
val binaryAst = output.toByteArray()
|
||||
|
||||
val scope = translationResult.fileMemberScopes[file] ?: error("Could not find descriptors for file: $file")
|
||||
val scope = fileTranslationResult.memberScope
|
||||
val metadataVersion = config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)
|
||||
val packagePart = KotlinJavascriptSerializationUtil.serializeDescriptors(
|
||||
bindingTrace.bindingContext, moduleDescriptor, scope, file.packageFqName,
|
||||
@@ -189,11 +191,21 @@ class K2JSTranslator(private val config: JsConfig) {
|
||||
metadataVersion ?: JsMetadataVersion.INSTANCE
|
||||
)
|
||||
|
||||
val header = serializeHeader(fileTranslationResult.inlineFunctionTags)
|
||||
|
||||
val ioFile = VfsUtilCore.virtualToIoFile(file.virtualFile)
|
||||
incrementalResults.processPackagePart(ioFile, packagePart.toByteArray(), binaryAst)
|
||||
incrementalResults.processPackagePart(ioFile, packagePart.toByteArray(), binaryAst, header)
|
||||
}
|
||||
|
||||
val settings = config.configuration.languageVersionSettings
|
||||
incrementalResults.processHeader(KotlinJavascriptSerializationUtil.serializeHeader(moduleDescriptor, null, settings).toByteArray())
|
||||
}
|
||||
|
||||
fun serializeHeader(importedTags: Set<String>): ByteArray {
|
||||
val output = ByteArrayOutputStream()
|
||||
val headerBuilder = JsAstProtoBuf.Header.newBuilder()
|
||||
headerBuilder.addAllInlineFunctionTags(importedTags)
|
||||
headerBuilder.build().writeTo(output)
|
||||
return output.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
sealed class TranslationUnit {
|
||||
class SourceFile(val file: KtFile) : TranslationUnit()
|
||||
|
||||
class BinaryAst(val data: ByteArray) : TranslationUnit()
|
||||
class BinaryAst(val data: ByteArray, val header: ByteArray) : TranslationUnit()
|
||||
}
|
||||
|
||||
@@ -518,6 +518,16 @@ public final class StaticContext {
|
||||
return localDescriptor != null && DescriptorUtils.getContainingModule(localDescriptor) == currentModule;
|
||||
}
|
||||
|
||||
private final Set<String> inlineFunctionTags = new HashSet<>();
|
||||
|
||||
@NotNull public Set<String> getInlineFunctionTags() {
|
||||
return inlineFunctionTags;
|
||||
}
|
||||
|
||||
public void reportInlineFunctionTag(@NotNull String tag) {
|
||||
inlineFunctionTags.add(tag);
|
||||
}
|
||||
|
||||
private final class InnerNameGenerator extends Generator<JsName> {
|
||||
public InnerNameGenerator() {
|
||||
addRule(descriptor -> {
|
||||
|
||||
@@ -958,4 +958,8 @@ public class TranslationContext {
|
||||
public LanguageVersionSettings getLanguageVersionSettings() {
|
||||
return CommonConfigurationKeysKt.getLanguageVersionSettings(staticContext.getConfig().getConfiguration());
|
||||
}
|
||||
|
||||
public void reportInlineFunctionTag(@NotNull String tag) {
|
||||
staticContext.reportInlineFunctionTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
|
||||
val inliningContext = context.inlineFunctionContext!!
|
||||
val block = JsBlock(inliningContext.importBlock.statements + inliningContext.prototypeBlock.statements +
|
||||
inliningContext.declarationsBlock.statements + JsReturn(function))
|
||||
context.reportInlineFunctionTag(tag.value);
|
||||
return InlineMetadata(tag, FunctionWithWrapper(function, block))
|
||||
}
|
||||
|
||||
|
||||
+62
-14
@@ -19,28 +19,76 @@ package org.jetbrains.kotlin.js.translate.general
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.TranslationUnit
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstDeserializer
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
import java.util.HashSet
|
||||
|
||||
class AstGenerationResult(
|
||||
val fragments: List<JsProgramFragment>,
|
||||
val fragmentMap: Map<KtFile, JsProgramFragment>,
|
||||
val newFragments: List<JsProgramFragment>,
|
||||
val fileMemberScopes: Map<KtFile, List<DeclarationDescriptor>>,
|
||||
private val program: JsProgram,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val moduleId: String,
|
||||
private val moduleKind: ModuleKind
|
||||
val units: Collection<TranslationUnit>,
|
||||
val translatedSourceFiles: Map<TranslationUnit.SourceFile, SourceFileTranslationResult>,
|
||||
val inlineFunctionTagMap: Map<String, TranslationUnit>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
config: JsConfig
|
||||
) {
|
||||
|
||||
val innerModuleName = program.getScope().declareName("_");
|
||||
// TODO remove
|
||||
val newFragments = translatedSourceFiles.values.map { it.fragment }
|
||||
|
||||
// Only available after the merge
|
||||
val importedModuleList: List<JsImportedModule>
|
||||
get() = fragments.flatMap { it.importedModules }
|
||||
get() = merger.importedModules
|
||||
|
||||
val innerModuleName: JsName
|
||||
get() = merger.internalModuleName
|
||||
|
||||
private val cache = mutableMapOf<TranslationUnit.BinaryAst, DeserializedFileTranslationResult>()
|
||||
|
||||
private val merger = Merger(moduleDescriptor, config.moduleId, config.moduleKind)
|
||||
|
||||
private val sourceRoots = config.sourceMapRoots.map { File(it) }
|
||||
private val deserializer = JsAstDeserializer(merger.program, sourceRoots)
|
||||
|
||||
fun translate(unit: TranslationUnit) =
|
||||
when (unit) {
|
||||
is TranslationUnit.SourceFile -> translatedSourceFiles[unit]!!
|
||||
is TranslationUnit.BinaryAst -> cache.getOrPut(unit) {
|
||||
// TODO Don't deserialize header twice
|
||||
val headerData = unit.header
|
||||
val header = JsAstProtoBuf.Header.parseFrom(CodedInputStream.newInstance(headerData))
|
||||
|
||||
DeserializedFileTranslationResult(
|
||||
deserializer.deserialize(ByteArrayInputStream(unit.data)),
|
||||
HashSet(header.inlineFunctionTagsList)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun buildProgram(): JsProgram {
|
||||
val merger = Merger(program, innerModuleName, moduleDescriptor, moduleId, moduleKind)
|
||||
val fragments = units.map { translate(it).fragment }
|
||||
fragments.forEach { merger.addFragment(it) }
|
||||
return merger.buildProgram()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class FileTranslationResult {
|
||||
abstract val fragment: JsProgramFragment
|
||||
|
||||
abstract val inlineFunctionTags: Set<String>
|
||||
}
|
||||
|
||||
class SourceFileTranslationResult(
|
||||
override val fragment: JsProgramFragment,
|
||||
override val inlineFunctionTags: Set<String>,
|
||||
val memberScope: List<DeclarationDescriptor>
|
||||
) : FileTranslationResult()
|
||||
|
||||
class DeserializedFileTranslationResult(
|
||||
override val fragment: JsProgramFragment,
|
||||
override val inlineFunctionTags: Set<String>
|
||||
) : FileTranslationResult()
|
||||
|
||||
|
||||
@@ -29,12 +29,14 @@ import org.jetbrains.kotlin.js.translate.utils.definePackageAlias
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
|
||||
class Merger(
|
||||
val program: JsProgram,
|
||||
val internalModuleName: JsName,
|
||||
val module: ModuleDescriptor,
|
||||
val moduleId: String,
|
||||
val moduleKind: ModuleKind
|
||||
) {
|
||||
val program: JsProgram = JsProgram()
|
||||
|
||||
val internalModuleName = program.scope.declareName("_")
|
||||
|
||||
private val rootFunction = JsFunction(program.rootScope, JsBlock(), "root function").also {
|
||||
it.parameters.add(JsParameter(internalModuleName))
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.js.facade.exceptions.UnsupportedFeatureException;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext;
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
@@ -48,6 +47,7 @@ import org.jetbrains.kotlin.js.translate.utils.*;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream;
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
@@ -58,17 +58,14 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstDeserializer;
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.jetbrains.kotlin.js.translate.general.ModuleWrapperTranslation.wrapIfNecessary;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.toStringLiteralList;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression;
|
||||
@@ -323,51 +320,43 @@ public final class Translation {
|
||||
@NotNull ModuleDescriptor moduleDescriptor,
|
||||
@NotNull JsConfig config,
|
||||
@NotNull SourceFilePathResolver sourceFilePathResolver
|
||||
) {
|
||||
) throws IOException {
|
||||
|
||||
JsProgram program = new JsProgram();
|
||||
Map<String, TranslationUnit> inlineFunctionTagMap = new HashMap<>();
|
||||
|
||||
Map<KtFile, JsProgramFragment> fragmentMap = new HashMap<>();
|
||||
List<JsProgramFragment> fragments = new ArrayList<>();
|
||||
List<JsProgramFragment> newFragments = new ArrayList<>();
|
||||
Map<TranslationUnit.SourceFile, SourceFileTranslationResult> translatedSourceFiles = new HashMap<>();
|
||||
|
||||
Map<KtFile, List<DeclarationDescriptor>> fileMemberScopes = new HashMap<>();
|
||||
|
||||
List<File> sourceRoots = config.getSourceMapRoots().stream().map(File::new).collect(Collectors.toList());
|
||||
JsAstDeserializer deserializer = new JsAstDeserializer(program, sourceRoots);
|
||||
for (TranslationUnit unit : units) {
|
||||
if (unit instanceof TranslationUnit.SourceFile) {
|
||||
KtFile file = ((TranslationUnit.SourceFile) unit).getFile();
|
||||
TranslationUnit.SourceFile sourceFileUnit = ((TranslationUnit.SourceFile) unit);
|
||||
KtFile file = sourceFileUnit.getFile();
|
||||
StaticContext staticContext = new StaticContext(bindingTrace, config, moduleDescriptor, sourceFilePathResolver, file.getPackageFqName().asString());
|
||||
TranslationContext context = TranslationContext.rootContext(staticContext);
|
||||
List<DeclarationDescriptor> fileMemberScope = new ArrayList<>();
|
||||
translateFile(context, file, fileMemberScope);
|
||||
|
||||
JsProgramFragment fragment = staticContext.getFragment();
|
||||
for (String tag : staticContext.getInlineFunctionTags()) {
|
||||
inlineFunctionTagMap.put(tag, unit);
|
||||
}
|
||||
|
||||
fragment.setTests(mayBeGenerateTests(context, file, fileMemberScope));
|
||||
fragment.setMainFunction(maybeGenerateCallToMain(context, config, moduleDescriptor, fileMemberScope, mainCallParameters));
|
||||
|
||||
fragments.add(fragment);
|
||||
newFragments.add(fragment);
|
||||
fragmentMap.put(file, fragment);
|
||||
fileMemberScopes.put(file, fileMemberScope);
|
||||
translatedSourceFiles.put(sourceFileUnit, new SourceFileTranslationResult(fragment, staticContext.getInlineFunctionTags(), fileMemberScope));
|
||||
}
|
||||
else if (unit instanceof TranslationUnit.BinaryAst) {
|
||||
byte[] astData = ((TranslationUnit.BinaryAst) unit).getData();
|
||||
JsProgramFragment fragment = deserializer.deserialize(new ByteArrayInputStream(astData));
|
||||
fragments.add(fragment);
|
||||
byte[] headerData = ((TranslationUnit.BinaryAst) unit).getHeader();
|
||||
JsAstProtoBuf.Header h = JsAstProtoBuf.Header.parseFrom(CodedInputStream.newInstance(headerData));
|
||||
for (String tag : h.getInlineFunctionTagsList()) {
|
||||
inlineFunctionTagMap.put(tag, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AstGenerationResult(fragments,
|
||||
fragmentMap,
|
||||
newFragments,
|
||||
fileMemberScopes,
|
||||
program,
|
||||
return new AstGenerationResult(units,
|
||||
translatedSourceFiles,
|
||||
inlineFunctionTagMap,
|
||||
moduleDescriptor,
|
||||
config.getModuleId(),
|
||||
config.getModuleKind());
|
||||
config);
|
||||
}
|
||||
|
||||
private static void translateFile(
|
||||
|
||||
Reference in New Issue
Block a user