JS: optimize default arguments in cross-module inliner
This reduces size of circlet UI (of approx 2.5 mb) by about 90 kb
This commit is contained in:
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.js.parser.parseFunction
|
||||
import org.jetbrains.kotlin.js.parser.sourcemaps.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
|
||||
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
|
||||
@@ -243,6 +244,7 @@ class FunctionReader(
|
||||
replaceExternalNames(function, replacements, allDefinedNames)
|
||||
wrapperStatements?.forEach { replaceExternalNames(it, replacements, allDefinedNames) }
|
||||
function.markInlineArguments(descriptor)
|
||||
markDefaultParams(function)
|
||||
|
||||
info.wrapFunctionVariable.let { wrapFunction ->
|
||||
for (externalName in (collectReferencedNames(function) - allDefinedNames).filter { it.ident == wrapFunction }) {
|
||||
@@ -270,6 +272,26 @@ class FunctionReader(
|
||||
|
||||
return FunctionWithWrapper(function, wrapper)
|
||||
}
|
||||
|
||||
private fun markDefaultParams(function: JsFunction) {
|
||||
val paramsByNames = function.parameters.associate { it.name to it }
|
||||
for (ifStatement in function.body.statements) {
|
||||
if (ifStatement !is JsIf || ifStatement.elseStatement != null) break
|
||||
val thenStatement = ifStatement.thenStatement as? JsExpressionStatement ?: break
|
||||
val testExpression = ifStatement.ifExpression as? JsBinaryOperation ?: break
|
||||
|
||||
if (testExpression.operator != JsBinaryOperator.REF_EQ) break
|
||||
val testLhs = testExpression.arg1 as? JsNameRef ?: break
|
||||
val param = paramsByNames[testLhs.name] ?: break
|
||||
if (testLhs.qualifier != null) break
|
||||
if ((testExpression.arg2 as? JsPrefixOperation)?.operator != JsUnaryOperator.VOID) break
|
||||
|
||||
val (assignLhs) = JsAstUtils.decomposeAssignmentToVariable(thenStatement.expression) ?: break
|
||||
if (assignLhs != testLhs.name) break
|
||||
|
||||
param.hasDefaultValue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val Char.isWhitespaceOrComma: Boolean
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
||||
|
||||
import org.jetbrains.kotlin.js.inline.context.NamingContext
|
||||
import org.jetbrains.kotlin.js.inline.util.rewriters.LabelNameRefreshingVisitor
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
|
||||
fun aliasArgumentsIfNeeded(
|
||||
context: NamingContext,
|
||||
@@ -30,7 +31,12 @@ fun aliasArgumentsIfNeeded(
|
||||
) {
|
||||
require(arguments.size <= parameters.size) { "arguments.size (${arguments.size}) should be less or equal to parameters.size (${parameters.size})" }
|
||||
|
||||
val defaultParams = mutableListOf<JsParameter>()
|
||||
for ((arg, param) in arguments.zip(parameters)) {
|
||||
if (JsAstUtils.isUndefinedExpression(arg)) {
|
||||
defaultParams += param
|
||||
continue
|
||||
}
|
||||
val paramName = param.name
|
||||
|
||||
val replacement = JsScope.declareTemporaryName(paramName.ident).apply {
|
||||
@@ -42,7 +48,7 @@ fun aliasArgumentsIfNeeded(
|
||||
context.replaceName(paramName, replacement)
|
||||
}
|
||||
|
||||
val defaultParams = parameters.subList(arguments.size, parameters.size)
|
||||
defaultParams += parameters.subList(arguments.size, parameters.size)
|
||||
for (defaultParam in defaultParams) {
|
||||
val paramName = defaultParam.name
|
||||
val freshName = JsScope.declareTemporaryName(paramName.ident)
|
||||
|
||||
@@ -5096,6 +5096,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiModuleDefaultArgsCleanup.kt")
|
||||
public void testMultiModuleDefaultArgsCleanup() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineSizeReduction/multiModuleDefaultArgsCleanup.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noDuplicateVariableDeclaration.kt")
|
||||
public void testNoDuplicateVariableDeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineSizeReduction/noDuplicateVariableDeclaration.kt");
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1018
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
inline fun foo(x: String = "x", y: String = "y") = x + y
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
// CHECK_VARS_COUNT: function=test count=0
|
||||
|
||||
fun test() = foo() + ";" + foo(x = "X") + ";" + foo(y = "Y") + ";" + foo(x = "X", y = "Y")
|
||||
|
||||
fun box(): String {
|
||||
val r = test()
|
||||
if (test() != "xy;Xy;xY;XY") return "fail: $r"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user