JS: replace declareFreshName with declareTemporaryName in inliner, get rid of scopes where possible
This commit is contained in:
@@ -52,7 +52,6 @@ import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.*
|
|||||||
* and precedes inline call (in JavaScript evaluation order).
|
* and precedes inline call (in JavaScript evaluation order).
|
||||||
*/
|
*/
|
||||||
internal class ExpressionDecomposer private constructor(
|
internal class ExpressionDecomposer private constructor(
|
||||||
private val scope: JsScope,
|
|
||||||
private val containsExtractable: Set<JsNode>,
|
private val containsExtractable: Set<JsNode>,
|
||||||
private val containsNodeWithSideEffect: Set<JsNode>
|
private val containsNodeWithSideEffect: Set<JsNode>
|
||||||
) : JsExpressionVisitor() {
|
) : JsExpressionVisitor() {
|
||||||
@@ -60,16 +59,14 @@ internal class ExpressionDecomposer private constructor(
|
|||||||
private var additionalStatements: MutableList<JsStatement> = SmartList()
|
private var additionalStatements: MutableList<JsStatement> = SmartList()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun preserveEvaluationOrder(
|
@JvmStatic fun preserveEvaluationOrder(statement: JsStatement, canBeExtractedByInliner: (JsNode) -> Boolean): List<JsStatement> {
|
||||||
scope: JsScope, statement: JsStatement, canBeExtractedByInliner: (JsNode)->Boolean
|
|
||||||
): List<JsStatement> {
|
|
||||||
val decomposer = with (statement) {
|
val decomposer = with (statement) {
|
||||||
val extractable = match(canBeExtractedByInliner)
|
val extractable = match(canBeExtractedByInliner)
|
||||||
val containsExtractable = withParentsOfNodes(extractable)
|
val containsExtractable = withParentsOfNodes(extractable)
|
||||||
val nodesWithSideEffect = match { it !is JsLiteral.JsValueLiteral }
|
val nodesWithSideEffect = match { it !is JsLiteral.JsValueLiteral }
|
||||||
val containsNodeWithSideEffect = withParentsOfNodes(nodesWithSideEffect)
|
val containsNodeWithSideEffect = withParentsOfNodes(nodesWithSideEffect)
|
||||||
|
|
||||||
ExpressionDecomposer(scope, containsExtractable, containsNodeWithSideEffect)
|
ExpressionDecomposer(containsExtractable, containsNodeWithSideEffect)
|
||||||
}
|
}
|
||||||
|
|
||||||
decomposer.accept(statement)
|
decomposer.accept(statement)
|
||||||
@@ -132,7 +129,7 @@ internal class ExpressionDecomposer private constructor(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// See KT-12275
|
// See KT-12275
|
||||||
val guardName = scope.declareFreshName("guard\$${(loopLabel?.ident.orEmpty())}")
|
val guardName = JsScope.declareTemporaryName("guard\$${(loopLabel?.ident.orEmpty())}")
|
||||||
val label = JsLabel(guardName).apply { synthetic = true }
|
val label = JsLabel(guardName).apply { synthetic = true }
|
||||||
label.statement = JsBlock(bodyStatements)
|
label.statement = JsBlock(bodyStatements)
|
||||||
addStatements(0, listOf(label))
|
addStatements(0, listOf(label))
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ private constructor(
|
|||||||
var thisReplacement = getThisReplacement(call)
|
var thisReplacement = getThisReplacement(call)
|
||||||
if (thisReplacement == null || thisReplacement is JsLiteral.JsThisRef) return
|
if (thisReplacement == null || thisReplacement is JsLiteral.JsThisRef) return
|
||||||
|
|
||||||
val thisName = namingContext.getFreshName(getThisAlias())
|
val thisName = JsScope.declareTemporaryName(getThisAlias())
|
||||||
namingContext.newVar(thisName, thisReplacement)
|
namingContext.newVar(thisName, thisReplacement)
|
||||||
thisReplacement = thisName.makeRef()
|
thisReplacement = thisName.makeRef()
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ private constructor(
|
|||||||
private fun processReturns() {
|
private fun processReturns() {
|
||||||
resultExpr = getResultReference()
|
resultExpr = getResultReference()
|
||||||
|
|
||||||
val breakName = namingContext.getFreshName(getBreakLabel())
|
val breakName = JsScope.declareTemporaryName(getBreakLabel())
|
||||||
this.breakLabel = JsLabel(breakName).apply { synthetic = true }
|
this.breakLabel = JsLabel(breakName).apply { synthetic = true }
|
||||||
|
|
||||||
val visitor = ReturnReplacingVisitor(resultExpr as? JsNameRef, breakName.makeRef(), invokedFunction, call.isSuspend)
|
val visitor = ReturnReplacingVisitor(resultExpr as? JsNameRef, breakName.makeRef(), invokedFunction, call.isSuspend)
|
||||||
@@ -119,7 +119,7 @@ private constructor(
|
|||||||
private fun getResultReference(): JsNameRef? {
|
private fun getResultReference(): JsNameRef? {
|
||||||
if (!isResultNeeded(call)) return null
|
if (!isResultNeeded(call)) return null
|
||||||
|
|
||||||
val resultName = namingContext.getFreshName(getResultLabel())
|
val resultName = JsScope.declareTemporaryName(getResultLabel())
|
||||||
this.resultName = resultName
|
this.resultName = resultName
|
||||||
namingContext.newVar(resultName, null)
|
namingContext.newVar(resultName, null)
|
||||||
return resultName.makeRef()
|
return resultName.makeRef()
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
FunctionReader functionReader = new FunctionReader((LibrarySourcesConfig) config, currentModuleName, fragments);
|
FunctionReader functionReader = new FunctionReader((LibrarySourcesConfig) config, currentModuleName, fragments);
|
||||||
JsInliner inliner = new JsInliner(functions, accessors, functionReader, trace);
|
JsInliner inliner = new JsInliner(functions, accessors, functionReader, trace);
|
||||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
inliner.inliningContexts.push(inliner.new JsInliningContext(null, fragment.getScope()));
|
inliner.inliningContexts.push(inliner.new JsInliningContext());
|
||||||
inliner.accept(fragment.getDeclarationBlock());
|
inliner.accept(fragment.getDeclarationBlock());
|
||||||
|
|
||||||
// There can be inlined function in top-level initializers, we need to optimize them as well
|
// There can be inlined function in top-level initializers, we need to optimize them as well
|
||||||
@@ -106,7 +106,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) {
|
public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) {
|
||||||
inliningContexts.push(new JsInliningContext(function, function.getScope()));
|
inliningContexts.push(new JsInliningContext());
|
||||||
assert !inProcessFunctions.contains(function): "Inliner has revisited function";
|
assert !inProcessFunctions.contains(function): "Inliner has revisited function";
|
||||||
inProcessFunctions.add(function);
|
inProcessFunctions.add(function);
|
||||||
|
|
||||||
@@ -181,12 +181,11 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
// at top level of js ast, contexts stack can be empty,
|
// at top level of js ast, contexts stack can be empty,
|
||||||
// but there is no inline calls anyway
|
// but there is no inline calls anyway
|
||||||
if(!inliningContexts.isEmpty()) {
|
if(!inliningContexts.isEmpty()) {
|
||||||
JsScope scope = getFunctionContext().getScope();
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (i < statements.size()) {
|
while (i < statements.size()) {
|
||||||
List<JsStatement> additionalStatements =
|
List<JsStatement> additionalStatements =
|
||||||
ExpressionDecomposer.preserveEvaluationOrder(scope, statements.get(i), canBeExtractedByInliner);
|
ExpressionDecomposer.preserveEvaluationOrder(statements.get(i), canBeExtractedByInliner);
|
||||||
statements.addAll(i, additionalStatements);
|
statements.addAll(i, additionalStatements);
|
||||||
i += additionalStatements.size() + 1;
|
i += additionalStatements.size() + 1;
|
||||||
}
|
}
|
||||||
@@ -286,8 +285,8 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
private class JsInliningContext implements InliningContext {
|
private class JsInliningContext implements InliningContext {
|
||||||
private final FunctionContext functionContext;
|
private final FunctionContext functionContext;
|
||||||
|
|
||||||
JsInliningContext(@NotNull JsScope scope) {
|
JsInliningContext() {
|
||||||
functionContext = new FunctionContext(scope) {
|
functionContext = new FunctionContext(functionReader) {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) {
|
protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) {
|
||||||
@@ -305,8 +304,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public NamingContext newNamingContext() {
|
public NamingContext newNamingContext() {
|
||||||
JsScope scope = getFunctionContext().getScope();
|
return new NamingContext(getStatementContext());
|
||||||
return new NamingContext(scope, getStatementContext());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.js.inline.FunctionReader
|
|||||||
import org.jetbrains.kotlin.js.inline.util.*
|
import org.jetbrains.kotlin.js.inline.util.*
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
|
|
||||||
abstract class FunctionContext(
|
abstract class FunctionContext(private val functionReader: FunctionReader) {
|
||||||
private val scope: JsScope,
|
|
||||||
private val functionReader: FunctionReader
|
|
||||||
) {
|
|
||||||
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
|
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
|
||||||
|
|
||||||
protected abstract fun lookUpStaticFunctionByTag(functionTag: String): JsFunction?
|
protected abstract fun lookUpStaticFunctionByTag(functionTag: String): JsFunction?
|
||||||
@@ -39,10 +36,6 @@ abstract class FunctionContext(
|
|||||||
return getFunctionDefinitionImpl(call) != null
|
return getFunctionDefinitionImpl(call) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getScope(): JsScope {
|
|
||||||
return scope
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets function definition by invocation.
|
* Gets function definition by invocation.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,10 +25,7 @@ import java.util.IdentityHashMap
|
|||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.kotlin.js.inline.util.replaceNames
|
import org.jetbrains.kotlin.js.inline.util.replaceNames
|
||||||
|
|
||||||
class NamingContext(
|
class NamingContext(private val statementContext: JsContext<JsStatement>) {
|
||||||
private val scope: JsScope,
|
|
||||||
private val statementContext: JsContext<JsStatement>
|
|
||||||
) {
|
|
||||||
private val renamings = IdentityHashMap<JsName, JsExpression>()
|
private val renamings = IdentityHashMap<JsName, JsExpression>()
|
||||||
private val declarations = ArrayList<JsVars>()
|
private val declarations = ArrayList<JsVars>()
|
||||||
private var addedDeclarations = false
|
private var addedDeclarations = false
|
||||||
@@ -48,8 +45,6 @@ class NamingContext(
|
|||||||
renamings.put(name, replacement)
|
renamings.put(name, replacement)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFreshName(candidate: String): JsName = scope.declareFreshName(candidate)
|
|
||||||
|
|
||||||
fun newVar(name: JsName, value: JsExpression? = null) {
|
fun newVar(name: JsName, value: JsExpression? = null) {
|
||||||
val vars = JsAstUtils.newVar(name, value)
|
val vars = JsAstUtils.newVar(name, value)
|
||||||
vars.synthetic = true
|
vars.synthetic = true
|
||||||
|
|||||||
Reference in New Issue
Block a user