JS: replace declareFreshName with declareTemporaryName in inliner, get rid of scopes where possible

This commit is contained in:
Alexey Andreev
2017-02-28 12:17:59 +03:00
parent 22f24d13b9
commit dc1ce0e8b5
5 changed files with 14 additions and 31 deletions
@@ -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