JS: during translation of expression mark assignment to temporary variables as synthetic statement.

This helps optimizer to find and eliminate temporary variables.
This commit is contained in:
Alexey Andreev
2016-05-10 12:22:40 +03:00
parent 82babaff7e
commit fe5a7aaf46
8 changed files with 69 additions and 25 deletions
@@ -133,7 +133,7 @@ public class JsFor extends SourceInfoAwareJsNode implements JsStatement {
if (initVars != null) {
result = new JsFor(initVars.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
} else {
result = new JsFor(initExpression.deepCopy(), conditionCopy, incrementExpression, bodyCopy);
result = new JsFor(initExpression.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
}
return result.withMetadataFrom(this);
@@ -121,6 +121,16 @@ internal class TemporaryAssignmentElimination(private val root: JsBlock) {
override fun visitBreak(x: JsBreak) { }
override fun visitContinue(x: JsContinue) { }
override fun visitFor(x: JsFor) {
x.initVars?.let { it.vars.forEach { it.initExpression?.let { accept(it) } } }
x.initExpression?.let { accept(it) }
x.condition?.let { accept(it) }
x.body?.let { accept(it) }
x.incrementExpression?.let { accept(it) }
super.visitFor(x)
}
}.accept(root)
usages.keys.retainAll(syntheticNames)
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.translate.context;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -57,11 +58,14 @@ public final class DynamicContext {
public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) {
if (vars == null) {
vars = new JsVars();
MetadataProperties.setSynthetic(vars, true);
currentBlock.getStatements().add(vars);
}
JsName temporaryName = currentScope.declareTemporary();
vars.add(new JsVar(temporaryName, null));
JsVar var = new JsVar(temporaryName, null);
MetadataProperties.setSynthetic(var, true);
vars.add(var);
return TemporaryVariable.create(temporaryName, initExpression);
}
@@ -16,9 +16,11 @@
package org.jetbrains.kotlin.js.translate.context;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
@@ -26,7 +28,12 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
public class TemporaryVariable {
/*package*/ static TemporaryVariable create(@NotNull JsName temporaryName, @Nullable JsExpression initExpression) {
return new TemporaryVariable(temporaryName, initExpression == null ? null : JsAstUtils.assignment(temporaryName.makeRef(), initExpression));
JsBinaryOperation rhs = null;
if (initExpression != null) {
rhs = JsAstUtils.assignment(temporaryName.makeRef(), initExpression);
MetadataProperties.setSynthetic(rhs, true);
}
return new TemporaryVariable(temporaryName, rhs);
}
@Nullable
@@ -29,9 +29,8 @@ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator;
import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
import org.jetbrains.kotlin.js.translate.expression.loopTranslator.LoopTranslator;
import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
import org.jetbrains.kotlin.js.translate.operation.BinaryOperationTranslator;
import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator;
@@ -16,14 +16,13 @@
@file:JvmName("LoopTranslator")
package org.jetbrains.kotlin.js.translate.expression.loopTranslator
package org.jetbrains.kotlin.js.translate.expression
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.DestructuringDeclarationTranslator
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.CompositeFIF
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getHasNextCallable
@@ -33,7 +32,6 @@ import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getTypeForExpression
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getLoopParameter
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getLoopRange
import org.jetbrains.kotlin.js.translate.utils.TemporariesUtils.temporariesInitialization
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
@@ -117,16 +115,16 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
val destructuringParameter: KtDestructuringDeclaration? = expression.destructuringParameter
fun declareParameter(): JsName {
fun declareParameter(): Pair<JsName, Boolean> {
val loopParameter = getLoopParameter(expression)
if (loopParameter != null) {
return context.getNameForElement(loopParameter)
return Pair(context.getNameForElement(loopParameter), false)
}
assert(destructuringParameter != null) { "If loopParameter is null, multi parameter must be not null ${expression.text}" }
return context.scope().declareTemporary()
return Pair(context.scope().declareTemporary(), true)
}
val parameterName: JsName = declareParameter()
val (parameterName, parameterIsTemporary) = declareParameter()
fun translateBody(itemValue: JsExpression?): JsStatement? {
val realBody = expression.body?.let { Translation.translateAsStatementAndMergeInBlockIfNeeded(it, context) }
@@ -135,10 +133,12 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
}
else {
val currentVarInit =
if (destructuringParameter == null)
if (destructuringParameter == null) {
newVar(parameterName, itemValue)
else
}
else {
DestructuringDeclarationTranslator.translate(destructuringParameter, parameterName, itemValue, context)
}
if (realBody == null) return JsBlock(currentVarInit)
@@ -170,12 +170,16 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
val rangeEnd = context.declareTemporary(rightExpression)
val body = translateBody(null)
val initExpression = newVar(parameterName, rangeStart)
val conditionExpression = lessThanEq(parameterName.makeRef(), rangeEnd.reference())
val incrementExpression = JsPostfixOperation(JsUnaryOperator.INC, parameterName.makeRef())
context.addStatementToCurrentBlock(temporariesInitialization(rangeEnd).makeStmt())
return JsFor(initExpression, conditionExpression, incrementExpression, body)
context.addStatementToCurrentBlock(asSyntheticStatement(rangeEnd.assignmentExpression()))
return if (parameterIsTemporary) {
JsFor(assignment(parameterName.makeRef(), rangeStart), conditionExpression, incrementExpression, body)
}
else {
JsFor(newVar(parameterName, rangeStart), conditionExpression, incrementExpression, body)
}
}
fun translateForOverRange(): JsStatement {
@@ -188,12 +192,21 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
val increment = context.declareTemporary(getProperty("step"))
val body = translateBody(null)
val initExpression = newVar(parameterName, start.reference())
val conditionExpression = lessThanEq(parameterName.makeRef(), end.reference())
val conditionExpression = lessThanEq(parameterName.makeRef(), end.reference())
val incrementExpression = addAssign(parameterName.makeRef(), increment.reference())
context.addStatementToCurrentBlock(temporariesInitialization(rangeExpression, start, end, increment).makeStmt())
return JsFor(initExpression, conditionExpression, incrementExpression, body)
context.addStatementToCurrentBlock(asSyntheticStatement(rangeExpression.assignmentExpression()))
context.addStatementToCurrentBlock(asSyntheticStatement(start.assignmentExpression()))
context.addStatementToCurrentBlock(asSyntheticStatement(end.assignmentExpression()))
context.addStatementToCurrentBlock(asSyntheticStatement(increment.assignmentExpression()))
return if (parameterIsTemporary) {
JsFor(assignment(parameterName.makeRef(), start.reference()), conditionExpression, incrementExpression, body)
}
else {
JsFor(newVar(parameterName, start.reference()), conditionExpression, incrementExpression, body)
}
}
fun translateForOverArray(): JsStatement {
@@ -204,11 +217,12 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
val arrayAccess = JsArrayAccess(rangeExpression.reference(), index.reference())
val body = translateBody(arrayAccess)
val initExpression = newVar(index.name(), context.program().getNumberLiteral(0))
val initExpression = assignment(index.name().makeRef(), context.program().getNumberLiteral(0))
val conditionExpression = inequality(index.reference(), end.reference())
val incrementExpression = JsPrefixOperation(JsUnaryOperator.INC, index.reference())
context.addStatementToCurrentBlock(temporariesInitialization(rangeExpression, end).makeStmt())
context.addStatementToCurrentBlock(asSyntheticStatement(rangeExpression.assignmentExpression()))
context.addStatementToCurrentBlock(asSyntheticStatement(end.assignmentExpression()))
return JsFor(initExpression, conditionExpression, incrementExpression, body)
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.translate.expression;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
@@ -57,9 +58,12 @@ public final class WhenTranslator extends AbstractTranslator {
KtExpression subject = expression.getSubjectExpression();
if (subject != null) {
JsExpression subjectExpression = Translation.translateAsExpression(subject, context);
if (TranslationUtils.isCacheNeeded(subjectExpression)) {
if (!JsAstUtils.isEmptyExpression(subjectExpression)) {
TemporaryVariable subjectVar = context.declareTemporary(null);
context.addStatementToCurrentBlock(JsAstUtils.assignment(subjectVar.reference(), subjectExpression).makeStmt());
JsExpressionStatement subjectAssignment = new JsExpressionStatement(
JsAstUtils.assignment(subjectVar.reference(), subjectExpression));
MetadataProperties.setSynthetic(subjectAssignment, true);
context.addStatementToCurrentBlock(subjectAssignment);
subjectExpression = subjectVar.reference();
}
expressionToMatch = subjectExpression;
@@ -302,6 +302,12 @@ public final class JsAstUtils {
return new JsBinaryOperation(JsBinaryOperator.ASG, left, right);
}
public static JsStatement asSyntheticStatement(@NotNull JsExpression expression) {
JsExpressionStatement statement = new JsExpressionStatement(expression);
MetadataProperties.setSynthetic(statement, true);
return statement;
}
@Nullable
public static Pair<JsExpression, JsExpression> decomposeAssignment(@NotNull JsExpression expr) {
if (!(expr instanceof JsBinaryOperation)) return null;