[JS IR] Add to IR keep possibility similar to legacy-dce one
It helps to: - keep declarations even if they are not reachable and not exported - not minify names of not exported declarations Compiler argument: -Xir-keep=A,B Can be used for top-level declarations or for member ^KT-54118 fixed
This commit is contained in:
+7
@@ -100,6 +100,13 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-target", valueDescription = "{ v5 }", description = "Generate JS files for specific ECMA version")
|
||||
var target: String? by NullableStringFreezableVar(null)
|
||||
|
||||
@Argument(
|
||||
value = "-Xir-keep",
|
||||
description = "Comma-separated list of fully-qualified names to not be eliminated by DCE (if it can be reached), " +
|
||||
"and for which to keep non-minified names."
|
||||
)
|
||||
var irKeep: String? by NullableStringFreezableVar(null)
|
||||
|
||||
@GradleOption(
|
||||
value = DefaultValues.JsModuleKinds::class,
|
||||
gradleInputType = GradleInputTypes.INPUT
|
||||
|
||||
@@ -100,6 +100,10 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
module,
|
||||
phaseConfig,
|
||||
irFactory,
|
||||
keep = arguments.irKeep?.split(",")
|
||||
?.filterNot { it.isEmpty() }
|
||||
?.toSet()
|
||||
?: emptySet(),
|
||||
dceRuntimeDiagnostic = RuntimeDiagnostic.resolve(
|
||||
arguments.irDceRuntimeDiagnostic,
|
||||
messageCollector
|
||||
|
||||
@@ -66,6 +66,7 @@ class JsIrBackendContext(
|
||||
val symbolTable: SymbolTable,
|
||||
irModuleFragment: IrModuleFragment,
|
||||
val additionalExportedDeclarationNames: Set<FqName>,
|
||||
keep: Set<String>,
|
||||
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
|
||||
override val scriptMode: Boolean = false,
|
||||
override val es6mode: Boolean = false,
|
||||
@@ -86,6 +87,9 @@ class JsIrBackendContext(
|
||||
val minimizedNameGenerator: MinimizedNameGenerator =
|
||||
MinimizedNameGenerator()
|
||||
|
||||
val keeper: Keeper =
|
||||
Keeper(keep)
|
||||
|
||||
val fieldDataCache = mutableMapOf<IrClass, Map<IrField, String>>()
|
||||
|
||||
override val builtIns = module.builtIns
|
||||
|
||||
@@ -51,6 +51,7 @@ fun compile(
|
||||
phaseConfig: PhaseConfig,
|
||||
irFactory: IrFactory,
|
||||
exportedDeclarations: Set<FqName> = emptySet(),
|
||||
keep: Set<String> = emptySet(),
|
||||
dceRuntimeDiagnostic: RuntimeDiagnostic? = null,
|
||||
es6mode: Boolean = false,
|
||||
verifySignatures: Boolean = true,
|
||||
@@ -76,6 +77,7 @@ fun compile(
|
||||
deserializer,
|
||||
phaseConfig,
|
||||
exportedDeclarations,
|
||||
keep,
|
||||
dceRuntimeDiagnostic,
|
||||
es6mode,
|
||||
baseClassIntoMetadata,
|
||||
@@ -97,6 +99,7 @@ fun compileIr(
|
||||
irLinker: JsIrLinker,
|
||||
phaseConfig: PhaseConfig,
|
||||
exportedDeclarations: Set<FqName>,
|
||||
keep: Set<String>,
|
||||
dceRuntimeDiagnostic: RuntimeDiagnostic?,
|
||||
es6mode: Boolean,
|
||||
baseClassIntoMetadata: Boolean,
|
||||
@@ -119,6 +122,7 @@ fun compileIr(
|
||||
symbolTable,
|
||||
allModules.first(),
|
||||
exportedDeclarations,
|
||||
keep,
|
||||
configuration,
|
||||
es6mode = es6mode,
|
||||
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
||||
@@ -126,7 +130,7 @@ fun compileIr(
|
||||
safeExternalBoolean = safeExternalBoolean,
|
||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||
granularity = granularity,
|
||||
icCompatibleIr2Js = if (icCompatibleIr2Js) IcCompatibleIr2Js.COMPATIBLE else IcCompatibleIr2Js.DISABLED
|
||||
icCompatibleIr2Js = if (icCompatibleIr2Js) IcCompatibleIr2Js.COMPATIBLE else IcCompatibleIr2Js.DISABLED,
|
||||
)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
|
||||
@@ -32,6 +32,7 @@ fun compileWithIC(
|
||||
filesToLower: Collection<IrFile>,
|
||||
mainArguments: List<String>? = null,
|
||||
exportedDeclarations: Set<FqName> = emptySet(),
|
||||
keep: Set<String> = emptySet(),
|
||||
generateFullJs: Boolean = true,
|
||||
generateDceJs: Boolean = false,
|
||||
dceDriven: Boolean = false,
|
||||
@@ -42,7 +43,7 @@ fun compileWithIC(
|
||||
baseClassIntoMetadata: Boolean = false,
|
||||
lowerPerModule: Boolean = false,
|
||||
safeExternalBoolean: Boolean = false,
|
||||
safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null
|
||||
safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null,
|
||||
): List<JsIrFragmentAndBinaryAst> {
|
||||
val irBuiltIns = mainModule.irBuiltins
|
||||
val symbolTable = (irBuiltIns as IrBuiltInsOverDescriptors).symbolTable
|
||||
@@ -53,13 +54,14 @@ fun compileWithIC(
|
||||
symbolTable,
|
||||
mainModule,
|
||||
exportedDeclarations,
|
||||
keep,
|
||||
configuration,
|
||||
es6mode = es6mode,
|
||||
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
||||
baseClassIntoMetadata = baseClassIntoMetadata,
|
||||
safeExternalBoolean = safeExternalBoolean,
|
||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||
icCompatibleIr2Js = IcCompatibleIr2Js.IC_MODE
|
||||
icCompatibleIr2Js = IcCompatibleIr2Js.IC_MODE,
|
||||
)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
|
||||
@@ -57,6 +57,7 @@ private fun IrDeclaration.addRootsTo(
|
||||
getter?.addRootsTo(nestedVisitor, context)
|
||||
setter?.addRootsTo(nestedVisitor, context)
|
||||
}
|
||||
|
||||
isEffectivelyExternal() -> {
|
||||
val correspondingProperty = when (this) {
|
||||
is IrField -> correspondingPropertySymbol?.owner
|
||||
@@ -68,15 +69,18 @@ private fun IrDeclaration.addRootsTo(
|
||||
acceptVoid(nestedVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
isExported(context) -> {
|
||||
acceptVoid(nestedVisitor)
|
||||
}
|
||||
|
||||
this is IrField -> {
|
||||
// TODO: simplify
|
||||
if ((initializer != null && !isKotlinPackage() || correspondingPropertySymbol?.owner?.isExported(context) == true) && !isConstant()) {
|
||||
acceptVoid(nestedVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
this is IrSimpleFunction -> {
|
||||
val correspondingProperty = correspondingPropertySymbol?.owner ?: return
|
||||
if (correspondingProperty.isExported(context)) {
|
||||
|
||||
+18
@@ -43,6 +43,7 @@ internal class JsUsefulDeclarationProcessor(
|
||||
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
||||
constructor.enqueue(data, "intrinsic: jsBoxIntrinsic")
|
||||
}
|
||||
|
||||
context.intrinsics.jsClass -> {
|
||||
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
||||
ref.enqueue(data, "intrinsic: jsClass")
|
||||
@@ -63,34 +64,42 @@ internal class JsUsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.reflectionSymbols.getKClassFromExpression -> {
|
||||
val ref = expression.getTypeArgument(0)?.classOrNull ?: context.irBuiltIns.anyClass
|
||||
referencedJsClassesFromExpressions += ref.owner
|
||||
}
|
||||
|
||||
context.intrinsics.jsObjectCreateSymbol -> {
|
||||
val classToCreate = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||
classToCreate.enqueue(data, "intrinsic: jsObjectCreateSymbol")
|
||||
constructedClasses += classToCreate
|
||||
}
|
||||
|
||||
context.intrinsics.jsEquals -> {
|
||||
equalsMethod.enqueue(data, "intrinsic: jsEquals")
|
||||
}
|
||||
|
||||
context.intrinsics.jsToString -> {
|
||||
toStringMethod.enqueue(data, "intrinsic: jsToString")
|
||||
}
|
||||
|
||||
context.intrinsics.jsHashCode -> {
|
||||
hashCodeMethod.enqueue(data, "intrinsic: jsHashCode")
|
||||
}
|
||||
|
||||
context.intrinsics.jsPlus -> {
|
||||
if (expression.getValueArgument(0)?.type?.classOrNull == context.irBuiltIns.stringClass) {
|
||||
toStringMethod.enqueue(data, "intrinsic: jsPlus")
|
||||
}
|
||||
}
|
||||
|
||||
context.intrinsics.jsConstruct -> {
|
||||
val callType = expression.getTypeArgument(0)!!
|
||||
val constructor = callType.getClass()!!.primaryConstructor
|
||||
constructor!!.enqueue(data, "ctor call from jsConstruct-intrinsic")
|
||||
}
|
||||
|
||||
context.intrinsics.es6DefaultType -> {
|
||||
//same as jsClass
|
||||
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
||||
@@ -104,6 +113,7 @@ internal class JsUsefulDeclarationProcessor(
|
||||
constructedClasses.add(klass)
|
||||
}
|
||||
}
|
||||
|
||||
context.intrinsics.jsInvokeSuspendSuperType,
|
||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
|
||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
|
||||
@@ -126,6 +136,14 @@ internal class JsUsefulDeclarationProcessor(
|
||||
override fun processClass(irClass: IrClass) {
|
||||
super.processClass(irClass)
|
||||
|
||||
if (context.keeper.shouldKeep(irClass)) {
|
||||
irClass.declarations
|
||||
.filter { context.keeper.shouldKeep(it) }
|
||||
.forEach { declaration ->
|
||||
declaration.enqueue(irClass, "kept declaration")
|
||||
}
|
||||
}
|
||||
|
||||
if (irClass.containsMetadata()) {
|
||||
when {
|
||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||
|
||||
+12
@@ -114,6 +114,18 @@ class IrModuleToJsTransformerTmp(
|
||||
}
|
||||
|
||||
private fun doStaticMembersLowering(modules: Iterable<IrModuleFragment>) {
|
||||
modules.forEach { module ->
|
||||
module.files.forEach {
|
||||
it.accept(
|
||||
backendContext.keeper,
|
||||
Keeper.KeepData(
|
||||
classInKeep = false,
|
||||
classShouldBeKept = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
modules.forEach { module ->
|
||||
module.files.forEach { StaticMembersLowering(backendContext).lower(it) }
|
||||
}
|
||||
|
||||
+9
-2
@@ -86,10 +86,15 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
||||
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
||||
require(function.dispatchReceiverParameter != null)
|
||||
val signature = jsFunctionSignature(function, context)
|
||||
if (context.keeper.shouldKeep(function)) {
|
||||
context.minimizedNameGenerator.keepName(signature)
|
||||
}
|
||||
val result = if (minimizedMemberNames && !function.hasStableJsName(context)) {
|
||||
function.parentAsClass.fieldData()
|
||||
context.minimizedNameGenerator.nameBySignature(signature)
|
||||
} else signature
|
||||
} else {
|
||||
signature
|
||||
}
|
||||
return result.toJsName()
|
||||
}
|
||||
|
||||
@@ -125,6 +130,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
||||
context.minimizedNameGenerator.reserveName(signature)
|
||||
}
|
||||
}
|
||||
|
||||
declaration is IrProperty -> {
|
||||
if (declaration.isExported(context)) {
|
||||
context.minimizedNameGenerator.reserveName(declaration.getJsNameOrKotlinName().identifier)
|
||||
@@ -146,7 +152,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
||||
correspondingProperty.isSimpleProperty
|
||||
val safeName = when {
|
||||
hasStableName -> (correspondingProperty ?: it).getJsNameOrKotlinName().identifier
|
||||
minimizedMemberNames -> context.minimizedNameGenerator.generateNextName()
|
||||
minimizedMemberNames && !context.keeper.shouldKeep(it) -> context.minimizedNameGenerator.generateNextName()
|
||||
else -> it.safeName()
|
||||
}
|
||||
val resultName = if (!hasStableName) {
|
||||
@@ -156,6 +162,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
||||
} else safeName
|
||||
result[it] = resultName
|
||||
}
|
||||
|
||||
it is IrFunction && it.dispatchReceiverParameter != null -> {
|
||||
nameCnt[jsFunctionSignature(it, context)] = 1 // avoid clashes with member functions
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
class Keeper(private val keep: Set<String>) : IrElementVisitor<Unit, Keeper.KeepData> {
|
||||
private val keptDeclarations: MutableSet<IrDeclaration> = mutableSetOf()
|
||||
|
||||
fun shouldKeep(declaration: IrDeclaration): Boolean {
|
||||
return declaration in keptDeclarations
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement, data: KeepData) {
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
/** Keep declarations can work both ways
|
||||
* if member of a class is in keep, the class should be also kept
|
||||
* if a class is kept, members of the class should be also kept
|
||||
* but there can be nested classes, and for nested classes we need only to propagate "keep" from top-level to nested (not vice versa)
|
||||
* because we have 2 directions, we need 2 boolean flags
|
||||
* [KeepData.classInKeep] responsible to propagate "keep" from class level to members direction
|
||||
* [KeepData.classShouldBeKept] responsible to bubble "keep" from members to class level direction
|
||||
*/
|
||||
override fun visitClass(declaration: IrClass, data: KeepData) {
|
||||
val prevShouldBeKept = data.classShouldBeKept
|
||||
val prevClassInKeep = data.classInKeep
|
||||
data.classShouldBeKept = false
|
||||
val keptClass = data.classInKeep || isInKeep(declaration)
|
||||
if (keptClass) {
|
||||
keptDeclarations.add(declaration)
|
||||
}
|
||||
data.classInKeep = keptClass
|
||||
super.visitClass(declaration, data)
|
||||
if (data.classShouldBeKept) {
|
||||
keptDeclarations.add(declaration)
|
||||
}
|
||||
data.classShouldBeKept = prevShouldBeKept
|
||||
data.classInKeep = prevClassInKeep
|
||||
}
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclarationBase, data: KeepData) {
|
||||
super.visitDeclaration(declaration, data)
|
||||
if (declaration in keptDeclarations) {
|
||||
return
|
||||
}
|
||||
if (declaration is IrDeclarationWithName && isInKeep(declaration) || data.classInKeep) {
|
||||
keptDeclarations.add(declaration)
|
||||
data.classShouldBeKept = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInKeep(declaration: IrDeclarationWithName): Boolean {
|
||||
return declaration.fqNameWhenAvailable?.asString() in keep
|
||||
}
|
||||
|
||||
class KeepData(var classInKeep: Boolean, var classShouldBeKept: Boolean)
|
||||
}
|
||||
+6
@@ -9,6 +9,7 @@ class MinimizedNameGenerator {
|
||||
private var index = 0
|
||||
private val functionSignatureToName = mutableMapOf<String, String>()
|
||||
private val reservedNames = mutableSetOf<String>()
|
||||
private val keptNames = mutableSetOf<String>()
|
||||
|
||||
fun generateNextName(): String {
|
||||
var candidate = index++.toJsIdentifier()
|
||||
@@ -19,11 +20,16 @@ class MinimizedNameGenerator {
|
||||
}
|
||||
|
||||
fun nameBySignature(signature: String): String {
|
||||
if (signature in keptNames) return signature
|
||||
return functionSignatureToName.getOrPut(signature) {
|
||||
generateNextName()
|
||||
}
|
||||
}
|
||||
|
||||
fun keepName(signature: String): Boolean {
|
||||
return keptNames.add(signature)
|
||||
}
|
||||
|
||||
fun reserveName(signature: String) {
|
||||
reservedNames.add(signature)
|
||||
}
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ where advanced options include:
|
||||
Enable runtime diagnostics when performing DCE instead of removing declarations
|
||||
-Xir-generate-inline-anonymous-functions
|
||||
Lambda expressions that capture values are translated into in-line anonymous JavaScript functions
|
||||
-Xir-keep Comma-separated list of fully-qualified names to not be eliminated by DCE (if it can be reached), and for which to keep non-minified names.
|
||||
-Xir-minimized-member-names Perform minimization for names of members
|
||||
-Xir-module-name=<name> Specify a compilation module name for IR backend
|
||||
-Xir-new-ir2js New fragment-based ir2js
|
||||
|
||||
+10
@@ -210,6 +210,11 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
|
||||
applicability = DirectiveApplicability.Global
|
||||
)
|
||||
|
||||
val ONLY_IR_DCE by directive(
|
||||
description = "Disable non DCE build",
|
||||
applicability = DirectiveApplicability.Global
|
||||
)
|
||||
|
||||
val RUN_IC by directive(
|
||||
description = "",
|
||||
applicability = DirectiveApplicability.Global
|
||||
@@ -251,4 +256,9 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
|
||||
""".trimIndent(),
|
||||
applicability = DirectiveApplicability.Global,
|
||||
)
|
||||
|
||||
val KEEP by stringDirective(
|
||||
description = "Keep declarations",
|
||||
applicability = DirectiveApplicability.Global
|
||||
)
|
||||
}
|
||||
|
||||
@@ -593,7 +593,15 @@ class GenerateIrRuntime {
|
||||
private fun doBackEnd(
|
||||
module: IrModuleFragment, symbolTable: SymbolTable, irBuiltIns: IrBuiltIns, jsLinker: JsIrLinker
|
||||
): CompilerResult {
|
||||
val context = JsIrBackendContext(module.descriptor, irBuiltIns, symbolTable, module, emptySet(), configuration)
|
||||
val context = JsIrBackendContext(
|
||||
module.descriptor,
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
module,
|
||||
additionalExportedDeclarationNames = emptySet(),
|
||||
keep = emptySet(),
|
||||
configuration
|
||||
)
|
||||
|
||||
ExternalDependenciesGenerator(symbolTable, listOf(jsLinker)).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ class JsIrBackendFacade(
|
||||
val splitPerFile = JsEnvironmentConfigurationDirectives.SPLIT_PER_FILE in module.directives
|
||||
val perModule = JsEnvironmentConfigurationDirectives.PER_MODULE in module.directives
|
||||
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
||||
val keep = module.directives[JsEnvironmentConfigurationDirectives.KEEP].toSet()
|
||||
|
||||
val granularity = when {
|
||||
!firstTimeCompilation -> JsGenerationGranularity.WHOLE_PROGRAM
|
||||
@@ -145,6 +146,7 @@ class JsIrBackendFacade(
|
||||
deserializer,
|
||||
phaseConfig,
|
||||
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))),
|
||||
keep = keep,
|
||||
dceRuntimeDiagnostic = null,
|
||||
es6mode = false,
|
||||
baseClassIntoMetadata = false,
|
||||
@@ -166,6 +168,7 @@ class JsIrBackendFacade(
|
||||
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
|
||||
.run { if (shouldBeGenerated()) arguments() else null }
|
||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
|
||||
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in module.directives
|
||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives
|
||||
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
||||
val perModuleOnly = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE in module.directives
|
||||
@@ -180,7 +183,7 @@ class JsIrBackendFacade(
|
||||
// If perModuleOnly then skip whole program
|
||||
// (it.dce => runIrDce) && (perModuleOnly => it.perModule)
|
||||
val translationModes = TranslationMode.values()
|
||||
.filter { (!it.dce || runIrDce) && (!perModuleOnly || it.perModule) }
|
||||
.filter { (it.dce || !onlyIrDce) && (!it.dce || runIrDce) && (!perModuleOnly || it.perModule) }
|
||||
.filter { it.dce == it.minimizedMemberNames }
|
||||
.toSet()
|
||||
val compilationOut = transformer.generateModule(loweredIr.allModules, translationModes, false)
|
||||
|
||||
@@ -33,8 +33,9 @@ class JsMinifierRunner(testServices: TestServices) : AbstractJsArtifactsCollecto
|
||||
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
|
||||
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
|
||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
|
||||
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in globalDirectives
|
||||
|
||||
if (dontRunGeneratedCode || esModules) return
|
||||
if (dontRunGeneratedCode || esModules || onlyIrDce) return
|
||||
|
||||
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.io.File
|
||||
class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
|
||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||
if (someAssertionWasFailed) return
|
||||
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
||||
|
||||
val globalDirectives = testServices.moduleStructure.allDirectives
|
||||
|
||||
@@ -31,8 +30,11 @@ class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCo
|
||||
val generateNodeJsRunner = JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER in globalDirectives
|
||||
val skipNodeJs = JsEnvironmentConfigurationDirectives.SKIP_NODE_JS in globalDirectives
|
||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
|
||||
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in globalDirectives
|
||||
|
||||
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs || esModules) return
|
||||
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs || esModules || onlyIrDce) return
|
||||
|
||||
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
||||
|
||||
val mainModuleName = getMainModuleName(testServices)
|
||||
val outputDir = File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).absolutePath)
|
||||
|
||||
@@ -136,10 +136,14 @@ fun getAllFilesForRunner(
|
||||
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }.filter { !File(it).isDirectory }
|
||||
val allJsFiles = additionalFiles + inputJsFilesBefore +artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
|
||||
|
||||
val result = mutableMapOf(TranslationMode.FULL to allJsFiles)
|
||||
val result = mutableMapOf<TranslationMode, List<String>>()
|
||||
|
||||
val globalDirectives = testServices.moduleStructure.allDirectives
|
||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in globalDirectives
|
||||
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in globalDirectives
|
||||
if (!onlyIrDce) {
|
||||
result[TranslationMode.FULL] = allJsFiles
|
||||
}
|
||||
if (runIrDce) {
|
||||
val dceJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, dceOutputDir.absolutePath) }
|
||||
val dceAllJsFiles = additionalFiles + inputJsFilesBefore + dceJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
|
||||
|
||||
@@ -6797,6 +6797,16 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/keep")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Keep {
|
||||
@Test
|
||||
public void testAllFilesPresentInKeep() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/keep"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+40
@@ -7269,6 +7269,46 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/keep")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Keep {
|
||||
@Test
|
||||
public void testAllFilesPresentInKeep() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/keep"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepClass.kt")
|
||||
public void testKeepClass() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepMethod.kt")
|
||||
public void testKeepMethod() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepMethod.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepNestedClass.kt")
|
||||
public void testKeepNestedClass() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepNestedClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepNestedClassIfKeptTopLevelClass.kt")
|
||||
public void testKeepNestedClassIfKeptTopLevelClass() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepNestedClassIfKeptTopLevelClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepOverriddenMethod.kt")
|
||||
public void testKeepOverriddenMethod() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepOverriddenMethod.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+40
@@ -7269,6 +7269,46 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/keep")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Keep {
|
||||
@Test
|
||||
public void testAllFilesPresentInKeep() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/keep"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepClass.kt")
|
||||
public void testKeepClass() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepMethod.kt")
|
||||
public void testKeepMethod() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepMethod.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepNestedClass.kt")
|
||||
public void testKeepNestedClass() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepNestedClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepNestedClassIfKeptTopLevelClass.kt")
|
||||
public void testKeepNestedClassIfKeptTopLevelClass() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepNestedClassIfKeptTopLevelClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("keepOverriddenMethod.kt")
|
||||
public void testKeepOverriddenMethod() throws Exception {
|
||||
runTest("js/js.translator/testData/box/keep/keepOverriddenMethod.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// ONLY_IR_DCE
|
||||
// RUN_PLAIN_BOX_FUNCTION
|
||||
// INFER_MAIN_MODULE
|
||||
// KEEP: A
|
||||
|
||||
// MODULE: keep_class
|
||||
// FILE: lib.kt
|
||||
|
||||
class A {
|
||||
fun foo(): String {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
fun bar(): String {
|
||||
return "bar"
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun bar(): A {
|
||||
return A()
|
||||
}
|
||||
|
||||
// FILE: test.js
|
||||
function box() {
|
||||
var a = this["keep_class"].bar()
|
||||
|
||||
if (a.foo_26di_k$() != "foo") return "fail 1"
|
||||
if (a.bar_232r_k$() != "bar") return "fail 2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// ONLY_IR_DCE
|
||||
// RUN_PLAIN_BOX_FUNCTION
|
||||
// INFER_MAIN_MODULE
|
||||
// KEEP: A.foo
|
||||
|
||||
// MODULE: keep_method
|
||||
// FILE: lib.kt
|
||||
|
||||
class A {
|
||||
fun foo(): String {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
fun bar(): String {
|
||||
return "bar"
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun bar(): A {
|
||||
return A()
|
||||
}
|
||||
|
||||
// FILE: test.js
|
||||
function box() {
|
||||
var a = this["keep_method"].bar()
|
||||
|
||||
if (a.foo_26di_k$() != "foo") return "fail 1"
|
||||
if (typeof a.bar_232r_k$ !== "undefined") return "fail 2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// ONLY_IR_DCE
|
||||
// RUN_PLAIN_BOX_FUNCTION
|
||||
// INFER_MAIN_MODULE
|
||||
// KEEP: A.B
|
||||
|
||||
// MODULE: keep_nested_class
|
||||
// FILE: lib.kt
|
||||
|
||||
class A {
|
||||
fun foo(): String {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
fun bar(): String {
|
||||
return "bar"
|
||||
}
|
||||
|
||||
class B {
|
||||
fun baz() = "baz"
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun barA(): A {
|
||||
return A()
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun bar(): A.B {
|
||||
return A.B()
|
||||
}
|
||||
|
||||
// FILE: test.js
|
||||
function box() {
|
||||
var a = this["keep_nested_class"].barA()
|
||||
var b = this["keep_nested_class"].bar()
|
||||
|
||||
if (typeof a.foo_26di_k$ !== "undefined") return "fail 1"
|
||||
if (typeof a.bar_232r_k$ !== "undefined") return "fail 2"
|
||||
if (b.baz_232z_k$() != "baz") return "fail 3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// ONLY_IR_DCE
|
||||
// RUN_PLAIN_BOX_FUNCTION
|
||||
// INFER_MAIN_MODULE
|
||||
// KEEP: A
|
||||
|
||||
// MODULE: keep_nested_class_if_kept_top_level_class
|
||||
// FILE: lib.kt
|
||||
|
||||
class A {
|
||||
fun foo(): String {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
fun bar(): String {
|
||||
return "bar"
|
||||
}
|
||||
|
||||
class B {
|
||||
fun baz() = "baz"
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun barA(): A {
|
||||
return A()
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun bar(): A.B {
|
||||
return A.B()
|
||||
}
|
||||
|
||||
// FILE: test.js
|
||||
function box() {
|
||||
var a = this["keep_nested_class_if_kept_top_level_class"].barA()
|
||||
var b = this["keep_nested_class_if_kept_top_level_class"].bar()
|
||||
|
||||
if (a.foo_26di_k$() != "foo") return "fail 1"
|
||||
if (a.bar_232r_k$() != "bar") return "fail 2"
|
||||
if (b.baz_232z_k$() != "baz") return "fail 3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// ONLY_IR_DCE
|
||||
// RUN_PLAIN_BOX_FUNCTION
|
||||
// INFER_MAIN_MODULE
|
||||
// KEEP: A.foo
|
||||
|
||||
// MODULE: keep_overridden_method
|
||||
// FILE: lib.kt
|
||||
|
||||
open class A {
|
||||
open fun foo(): String {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
open fun bar(): String {
|
||||
return "bar"
|
||||
}
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
override fun foo(): String {
|
||||
return super.foo() + "!"
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
fun bar(): B {
|
||||
return B()
|
||||
}
|
||||
|
||||
// FILE: test.js
|
||||
function box() {
|
||||
var b = this["keep_overridden_method"].bar()
|
||||
|
||||
if (b.foo_26di_k$() != "foo!") return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+2
-1
@@ -92,7 +92,8 @@ class JsCoreScriptingCompiler(
|
||||
psi2irContext.irBuiltIns,
|
||||
psi2irContext.symbolTable,
|
||||
irModuleFragment,
|
||||
emptySet(),
|
||||
additionalExportedDeclarationNames = emptySet(),
|
||||
keep = emptySet(),
|
||||
environment.configuration,
|
||||
true
|
||||
)
|
||||
|
||||
+2
-1
@@ -62,7 +62,8 @@ class JsScriptDependencyCompiler(
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
moduleFragment,
|
||||
emptySet(),
|
||||
additionalExportedDeclarationNames = emptySet(),
|
||||
keep = emptySet(),
|
||||
configuration,
|
||||
true
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user