From 83140bc5f754413e9d955011bed4591e618af9c7 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 10 Feb 2017 19:31:52 +0300 Subject: [PATCH] JS: support inlining in new pipeline --- .../kotlin/resolve/calls/util/callUtil.kt | 14 ++++-- .../js/backend/ast/JsProgramFragment.java | 6 +++ .../kotlin/js/inline/FunctionReader.kt | 26 ++++++----- .../jetbrains/kotlin/js/inline/JsInliner.java | 46 +++++++++++++------ .../js/inline/context/FunctionContext.kt | 4 +- .../kotlin/js/inline/util/collectUtils.kt | 17 +++++++ .../kotlin/js/facade/K2JSTranslator.java | 26 ++++++----- .../translate/context/DeclarationExporter.kt | 3 +- .../js/translate/context/StaticContext.java | 7 ++- .../translate/context/TranslationContext.java | 5 +- .../translate/general/AstGenerationResult.kt | 29 ++++++++++++ .../kotlin/js/translate/general/Merger.kt | 4 +- .../js/translate/general/Translation.java | 14 +++--- .../reference/VariableAccessTranslator.java | 11 ++--- .../kotlin/js/translate/utils/inlineUtils.kt | 7 ++- 15 files changed, 157 insertions(+), 62 deletions(-) create mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/general/AstGenerationResult.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt index 4797e2ed062..93d2d3c9329 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.callUtil import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -210,6 +207,15 @@ fun KtExpression.getPropertyResolvedCallWithAssert(context: BindingContext): Res return resolvedCall as ResolvedCall } +fun KtExpression.getVariableResolvedCallWithAssert(context: BindingContext): ResolvedCall { + val resolvedCall = getResolvedCallWithAssert(context) + assert(resolvedCall.resultingDescriptor is VariableDescriptor) { + "ResolvedCall for this expression must be ResolvedCall: ${this.getTextWithLocation()}" + } + @Suppress("UNCHECKED_CAST") + return resolvedCall as ResolvedCall +} + fun KtExpression.getType(context: BindingContext): KotlinType? { val type = context.getType(this) if (type != null) return type diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsProgramFragment.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsProgramFragment.java index 2cbc34a92ea..f5200fe307d 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsProgramFragment.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsProgramFragment.java @@ -17,6 +17,7 @@ public class JsProgramFragment { private final JsGlobalBlock initializerBlock = new JsGlobalBlock(); private final List nameBindings = new ArrayList(); private final Map classes = new LinkedHashMap(); + private final Map inlineModuleMap = new LinkedHashMap(); public JsProgramFragment(@NotNull JsScope scope) { this.scope = scope; @@ -61,4 +62,9 @@ public class JsProgramFragment { public Map getClasses() { return classes; } + + @NotNull + public Map getInlineModuleMap() { + return inlineModuleMap; + } } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt index 370834c7228..6417976ecac 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt @@ -27,9 +27,7 @@ import org.jetbrains.kotlin.js.inline.util.IdentitySet import org.jetbrains.kotlin.js.inline.util.isCallInvocation import org.jetbrains.kotlin.js.parser.parseFunction import org.jetbrains.kotlin.js.translate.context.Namer -import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.inline.InlineStrategy @@ -48,7 +46,7 @@ private val JS_IDENTIFIER="[$JS_IDENTIFIER_START][$JS_IDENTIFIER_PART]*" private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern() private val DEFINE_MODULE_FIND_PATTERN = ".defineModule(" -class FunctionReader(private val context: TranslationContext) { +class FunctionReader(private val config: LibrarySourcesConfig, private val currentModuleName: JsName, fragments: List) { /** * fileContent: .js file content, that contains this module definition. * One file can contain more than one module definition. @@ -63,8 +61,12 @@ class FunctionReader(private val context: TranslationContext) { private val moduleNameToInfo = HashMultimap.create() + private val moduleNameMap: Map + init { - val libs = context.config.libraries.map(::File) + val libs = config.libraries.map(::File) + + moduleNameMap = buildModuleNameMap(fragments) JsLibraryUtils.traverseJsLibraries(libs) { fileContent, _ -> var current = 0 @@ -86,6 +88,13 @@ class FunctionReader(private val context: TranslationContext) { } } + // Since we compile each source file in its own context (and we may loose these context when performing incremental compilation) + // we don't use contexts to generate proper names for modules. Instead, we generate all necessary information during + // translation and rely on it here. + private fun buildModuleNameMap(fragments: List): Map { + return fragments.flatMap { it.inlineModuleMap.entries }.associate { (k, v) -> k to v } + } + private fun rewindToIdentifierStart(text: String, index: Int): Int { var result = index while (result > 0 && Character.isJavaIdentifierPart(text[result - 1])) { @@ -112,7 +121,7 @@ class FunctionReader(private val context: TranslationContext) { operator fun contains(descriptor: CallableDescriptor): Boolean { val moduleName = getModuleName(descriptor) - val currentModuleName = context.config.moduleId + val currentModuleName = config.moduleId return currentModuleName != moduleName && moduleName in moduleNameToInfo.keys() } @@ -144,7 +153,7 @@ class FunctionReader(private val context: TranslationContext) { } val function = parseFunction(source, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram())) - val moduleReference = context.getModuleExpressionFor(descriptor) ?: getRootPackage() + val moduleReference = moduleNameMap[tag] ?: currentModuleName.makeRef() val replacements = hashMapOf(info.moduleVariable to moduleReference, info.kotlinVariable to Namer.kotlinObject()) @@ -152,11 +161,6 @@ class FunctionReader(private val context: TranslationContext) { function.markInlineArguments(descriptor) return function } - - private fun getRootPackage(): JsExpression { - val rootName = context.program().rootScope.declareName(Namer.getRootPackageName()) - return JsAstUtils.pureFqn(rootName, null) - } } private val Char.isWhitespaceOrComma: Boolean diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.java b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.java index 3040d2b5ff7..c2545952f61 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.java +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/JsInliner.java @@ -28,6 +28,8 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.js.backend.ast.*; import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties; +import org.jetbrains.kotlin.js.config.JsConfig; +import org.jetbrains.kotlin.js.config.LibrarySourcesConfig; import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor; import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedFunctionDefinitionsKt; import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedLocalFunctionDeclarationsKt; @@ -37,7 +39,6 @@ import org.jetbrains.kotlin.js.inline.context.NamingContext; import org.jetbrains.kotlin.js.inline.util.CollectUtilsKt; import org.jetbrains.kotlin.js.inline.util.CollectionUtilsKt; import org.jetbrains.kotlin.js.inline.util.NamingUtilsKt; -import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.resolve.inline.InlineStrategy; import java.util.*; @@ -61,15 +62,34 @@ public class JsInliner extends JsVisitorWithContextImpl { private final Function1 canBeExtractedByInliner = node -> node instanceof JsInvocation && hasToBeInlined((JsInvocation) node); - public static JsProgram process(@NotNull TranslationContext context) { - JsProgram program = context.program(); - Map functions = CollectUtilsKt.collectNamedFunctions(program); - Map accessors = CollectUtilsKt.collectAccessors(program); - new DummyAccessorInvocationTransformer().accept(program); - JsInliner inliner = new JsInliner(functions, accessors, new FunctionReader(context), context.bindingTrace()); - inliner.accept(program); - RemoveUnusedFunctionDefinitionsKt.removeUnusedFunctionDefinitions(program, functions); - return program; + public static void process( + @NotNull JsConfig config, + @NotNull DiagnosticSink trace, + @NotNull JsName currentModuleName, + @NotNull List fragments, + @NotNull List fragmentsToProcess + ) { + Map functions = CollectUtilsKt.collectNamedFunctions(fragments); + Map accessors = CollectUtilsKt.collectAccessors(fragments); + DummyAccessorInvocationTransformer accessorInvocationTransformer = new DummyAccessorInvocationTransformer(); + for (JsProgramFragment fragment : fragmentsToProcess) { + accessorInvocationTransformer.accept(fragment.getDeclarationBlock()); + accessorInvocationTransformer.accept(fragment.getInitializerBlock()); + } + FunctionReader functionReader = new FunctionReader((LibrarySourcesConfig) config, currentModuleName, fragments); + JsInliner inliner = new JsInliner(functions, accessors, functionReader, trace); + for (JsProgramFragment fragment : fragmentsToProcess) { + inliner.inliningContexts.push(inliner.new JsInliningContext(null, fragment.getScope())); + inliner.accept(fragment.getDeclarationBlock()); + + // There can be inlined function in top-level initializers, we need to optimize them as well + JsFunction fakeInitFunction = new JsFunction(JsDynamicScope.INSTANCE, fragment.getInitializerBlock(), ""); + inliner.accept(fakeInitFunction); + + inliner.inliningContexts.pop(); + JsBlock block = new JsBlock(fragment.getDeclarationBlock(), fragment.getInitializerBlock(), fragment.getExportBlock()); + RemoveUnusedFunctionDefinitionsKt.removeUnusedFunctionDefinitions(block, functions); + } } private JsInliner( @@ -86,7 +106,7 @@ public class JsInliner extends JsVisitorWithContextImpl { @Override public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) { - inliningContexts.push(new JsInliningContext(function)); + inliningContexts.push(new JsInliningContext(function, function.getScope())); assert !inProcessFunctions.contains(function): "Inliner has revisited function"; inProcessFunctions.add(function); @@ -266,8 +286,8 @@ public class JsInliner extends JsVisitorWithContextImpl { private class JsInliningContext implements InliningContext { private final FunctionContext functionContext; - JsInliningContext(@NotNull JsFunction function) { - functionContext = new FunctionContext(function, functionReader) { + JsInliningContext(@NotNull JsScope scope) { + functionContext = new FunctionContext(scope) { @Nullable @Override protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) { diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt index c03138d5520..e41ae888db2 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.js.inline.util.* import org.jetbrains.kotlin.js.translate.context.Namer abstract class FunctionContext( - private val function: JsFunction, + private val scope: JsScope, private val functionReader: FunctionReader ) { protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction? @@ -40,7 +40,7 @@ abstract class FunctionContext( } fun getScope(): JsScope { - return function.scope + return scope } /** diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/collectUtils.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/collectUtils.kt index 36f21e81920..3fd2390937b 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/collectUtils.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/collectUtils.kt @@ -137,6 +137,15 @@ fun collectNamedFunctions(scope: JsNode) = collectNamedFunctionsAndMetadata(scop fun collectNamedFunctionsOrMetadata(scope: JsNode) = collectNamedFunctionsAndMetadata(scope).mapValues { it.value.second } +fun collectNamedFunctions(fragments: List): Map { + val result = mutableMapOf() + for (fragment in fragments) { + result += collectNamedFunctions(fragment.declarationBlock) + result += collectNamedFunctions(fragment.initializerBlock) + } + return result +} + fun collectNamedFunctionsAndMetadata(scope: JsNode): Map> { val namedFunctions = mutableMapOf>() @@ -200,6 +209,14 @@ fun collectAccessors(scope: JsNode): Map { return accessors } +fun collectAccessors(fragments: List): Map { + val result = mutableMapOf() + for (fragment in fragments) { + result += collectAccessors(fragment.declarationBlock) + } + return result +} + fun collectInstances(klass: Class, scope: JsNode): List { return with(InstanceCollector(klass, visitNestedDeclarations = false)) { accept(scope) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java index e93c4bc5d69..72fbd880593 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java @@ -21,12 +21,14 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.ModuleDescriptor; import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS; import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult; -import org.jetbrains.kotlin.js.backend.ast.JsProgram; +import org.jetbrains.kotlin.js.backend.ast.JsImportedModule; import org.jetbrains.kotlin.js.config.JsConfig; import org.jetbrains.kotlin.js.coroutine.CoroutineTransformer; import org.jetbrains.kotlin.js.facade.exceptions.TranslationException; +import org.jetbrains.kotlin.js.inline.JsInliner; import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt; import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt; +import org.jetbrains.kotlin.js.translate.general.AstGenerationResult; import org.jetbrains.kotlin.js.translate.general.Translation; import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus; import org.jetbrains.kotlin.psi.KtFile; @@ -74,18 +76,20 @@ public final class K2JSTranslator { ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor(); Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics(); - JsProgram program = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config); + AstGenerationResult translationResult = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config); ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics); - //JsInliner.process(program); - ResolveTemporaryNamesKt.resolveTemporaryNames(program); + JsInliner.process(config, analysisResult.getBindingTrace(), translationResult.getInnerModuleName(), + translationResult.getFragments(), translationResult.getFragments()); + + ResolveTemporaryNamesKt.resolveTemporaryNames(translationResult.getProgram()); ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics); - CoroutineTransformer coroutineTransformer = new CoroutineTransformer(program); - coroutineTransformer.accept(program); - RemoveUnusedImportsKt.removeUnusedImports(program); + CoroutineTransformer coroutineTransformer = new CoroutineTransformer(translationResult.getProgram()); + coroutineTransformer.accept(translationResult.getProgram()); + RemoveUnusedImportsKt.removeUnusedImports(translationResult.getProgram()); ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics); @@ -93,10 +97,10 @@ public final class K2JSTranslator { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); List importedModules = new ArrayList<>(); - /*for (JsImportedModule module : context.getImportedModules()) { + for (JsImportedModule module : translationResult.getImportedModuleList()) { importedModules.add(module.getExternalName()); - }*/ - return new TranslationResult.Success(config, files, program, diagnostics, importedModules, moduleDescriptor, - bindingTrace.getBindingContext()); + } + return new TranslationResult.Success(config, files, translationResult.getProgram(), diagnostics, importedModules, + moduleDescriptor, bindingTrace.getBindingContext()); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt index 65a98779af9..763dd2b7d75 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt @@ -34,7 +34,8 @@ internal class DeclarationExporter(val context: StaticContext) { private val objectLikeKinds = setOf(ClassKind.OBJECT, ClassKind.ENUM_ENTRY) private val exportedDeclarations = mutableSetOf() private val localPackageNames = mutableMapOf() - val statements = mutableListOf() + private val statements: MutableList + get() = context.fragment.exportBlock.statements fun export(descriptor: MemberDescriptor, force: Boolean) { if (exportedDeclarations.contains(descriptor)) return diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index 740dc18eed1..12feb50f153 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -642,7 +642,7 @@ public final class StaticContext { } @Nullable - public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) { + private JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) { JsName name = getModuleInnerName(descriptor); return name != null ? JsAstUtils.pureFqn(name, null) : null; } @@ -748,6 +748,11 @@ public final class StaticContext { return currentModule; } + public void addInlineCall(@NotNull CallableDescriptor descriptor) { + String tag = Namer.getFunctionTag(descriptor); + fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor)); + } + /*public void postProcess() { addInterfaceDefaultMethods(); rootFunction.getBody().getStatements().addAll(importStatements); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 6db6177d11d..8855122c60c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -625,9 +625,8 @@ public class TranslationContext { callSites.add(new DeferredCallSite(constructor, invocationArgs, this)); } - @Nullable - public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) { - return staticContext.getModuleExpressionFor(descriptor); + public void addInlineCall(@NotNull CallableDescriptor descriptor) { + staticContext.addInlineCall(descriptor); } public void addDeclarationStatement(@NotNull JsStatement statement) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/AstGenerationResult.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/AstGenerationResult.kt new file mode 100644 index 00000000000..ae8843d134e --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/AstGenerationResult.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.translate.general + +import org.jetbrains.kotlin.js.backend.ast.JsImportedModule +import org.jetbrains.kotlin.js.backend.ast.JsName +import org.jetbrains.kotlin.js.backend.ast.JsProgram +import org.jetbrains.kotlin.js.backend.ast.JsProgramFragment + +class AstGenerationResult( + val program: JsProgram, + val innerModuleName: JsName, + val fragments: List, + val importedModuleList: List +) \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt index 062780e4c4c..b5a11f07530 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt @@ -16,12 +16,13 @@ package org.jetbrains.kotlin.js.translate.general +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName) { +class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName, val module: ModuleDescriptor) { // Maps unique signature (see generateSignature) to names private val nameTable = mutableMapOf() private val importedModuleTable = mutableMapOf() @@ -114,6 +115,7 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam this += importBlock.statements addClassPrototypes(this) this += declarationBlock.statements + this += exportBlock.statements this += initializerBlock.statements } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java index 5757ef7aadc..d3e96f6ae3c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java @@ -234,7 +234,7 @@ public final class Translation { } @NotNull - public static JsProgram generateAst( + public static AstGenerationResult generateAst( @NotNull BindingTrace bindingTrace, @NotNull Collection files, @NotNull MainCallParameters mainCallParameters, @@ -253,7 +253,7 @@ public final class Translation { } @NotNull - private static JsProgram doGenerateAst( + private static AstGenerationResult doGenerateAst( @NotNull BindingTrace bindingTrace, @NotNull Collection files, @NotNull MainCallParameters mainCallParameters, @@ -263,7 +263,7 @@ public final class Translation { JsProgram program = new JsProgram(); JsFunction rootFunction = new JsFunction(program.getRootScope(), new JsBlock(), "root function"); JsName internalModuleName = program.getScope().declareName("_"); - Merger merger = new Merger(rootFunction, internalModuleName); + Merger merger = new Merger(rootFunction, internalModuleName, moduleDescriptor); List fragments = new ArrayList(); for (KtFile file : files) { @@ -280,15 +280,13 @@ public final class Translation { List statements = rootBlock.getStatements(); - //staticContext.postProcess(); statements.add(0, program.getStringLiteral("use strict").makeStmt()); if (!isBuiltinModule(fragments)) { defineModule(program, statements, config.getModuleId()); } //mayBeGenerateTests(files, rootBlock, context); - JsName rootPackageName = program.getScope().declareName(Namer.getRootPackageName()); - rootFunction.getParameters().add(new JsParameter((rootPackageName))); + rootFunction.getParameters().add(new JsParameter(internalModuleName)); // Invoke function passing modules as arguments // This should help minifier tool to recognize references to these modules as local variables and make them shorter. @@ -307,13 +305,13 @@ public final class Translation { } */ - statements.add(new JsReturn(rootPackageName.makeRef())); + statements.add(new JsReturn(internalModuleName.makeRef())); JsBlock block = program.getGlobalBlock(); block.getStatements().addAll(wrapIfNecessary(config.getModuleId(), rootFunction, importedModuleList, program, config.getModuleKind())); - return program; + return new AstGenerationResult(program, internalModuleName, fragments, importedModuleList); } private static boolean isBuiltinModule(@NotNull List fragments) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java index d5193ac3686..74e6c5f6390 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/VariableAccessTranslator.java @@ -39,13 +39,12 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce @NotNull KtReferenceExpression referenceExpression, @Nullable JsExpression receiver ) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(referenceExpression, context.bindingContext()); + ResolvedCall resolvedCall = + CallUtilKt.getVariableResolvedCallWithAssert(referenceExpression, context.bindingContext()); if (resolvedCall instanceof VariableAsFunctionResolvedCall) { resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall(); } - assert resolvedCall.getResultingDescriptor() instanceof VariableDescriptor; - return new VariableAccessTranslator(context, referenceExpression, (ResolvedCall) resolvedCall, - receiver); + return new VariableAccessTranslator(context, referenceExpression, resolvedCall, receiver); } @@ -75,7 +74,7 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce if (InlineUtil.isInline(getter)) { if (e instanceof JsNameRef) { // Get was translated as a name reference - setInlineCallMetadata((JsNameRef) e, referenceExpression, getter); + setInlineCallMetadata((JsNameRef) e, referenceExpression, getter, context()); } else { setInlineCallMetadata(e, referenceExpression, getter, context()); } @@ -94,7 +93,7 @@ public class VariableAccessTranslator extends AbstractTranslator implements Acce if (InlineUtil.isInline(setter)) { if (e instanceof JsBinaryOperation && ((JsBinaryOperation) e).getOperator().isAssignment()) { // Set was translated as an assignment - setInlineCallMetadata((JsNameRef) (((JsBinaryOperation) e).getArg1()), referenceExpression, setter); + setInlineCallMetadata((JsNameRef) (((JsBinaryOperation) e).getArg1()), referenceExpression, setter, context()); } else { setInlineCallMetadata(e, referenceExpression, setter, context()); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt index 65135d545c7..d487013b5fb 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt @@ -64,6 +64,8 @@ fun setInlineCallMetadata( } visitor.accept(expression) + + context.addInlineCall(descriptor) } fun setInlineCallMetadata( @@ -76,11 +78,14 @@ fun setInlineCallMetadata( fun setInlineCallMetadata( nameRef: JsNameRef, psiElement: KtExpression, - descriptor: CallableDescriptor + descriptor: CallableDescriptor, + context: TranslationContext ) { nameRef.descriptor = descriptor nameRef.inlineStrategy = InlineStrategy.IN_PLACE nameRef.psiElement = psiElement + + context.addInlineCall(descriptor) } fun TranslationContext.aliasedName(descriptor: CallableDescriptor): JsName {