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:
@@ -133,7 +133,7 @@ public class JsFor extends SourceInfoAwareJsNode implements JsStatement {
|
|||||||
if (initVars != null) {
|
if (initVars != null) {
|
||||||
result = new JsFor(initVars.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
|
result = new JsFor(initVars.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
|
||||||
} else {
|
} else {
|
||||||
result = new JsFor(initExpression.deepCopy(), conditionCopy, incrementExpression, bodyCopy);
|
result = new JsFor(initExpression.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.withMetadataFrom(this);
|
return result.withMetadataFrom(this);
|
||||||
|
|||||||
+10
@@ -121,6 +121,16 @@ internal class TemporaryAssignmentElimination(private val root: JsBlock) {
|
|||||||
override fun visitBreak(x: JsBreak) { }
|
override fun visitBreak(x: JsBreak) { }
|
||||||
|
|
||||||
override fun visitContinue(x: JsContinue) { }
|
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)
|
}.accept(root)
|
||||||
|
|
||||||
usages.keys.retainAll(syntheticNames)
|
usages.keys.retainAll(syntheticNames)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.js.translate.context;
|
package org.jetbrains.kotlin.js.translate.context;
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -57,11 +58,14 @@ public final class DynamicContext {
|
|||||||
public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) {
|
public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) {
|
||||||
if (vars == null) {
|
if (vars == null) {
|
||||||
vars = new JsVars();
|
vars = new JsVars();
|
||||||
|
MetadataProperties.setSynthetic(vars, true);
|
||||||
currentBlock.getStatements().add(vars);
|
currentBlock.getStatements().add(vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsName temporaryName = currentScope.declareTemporary();
|
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);
|
return TemporaryVariable.create(temporaryName, initExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.context;
|
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.JsExpression;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
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.JsNameRef;
|
||||||
|
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||||
@@ -26,7 +28,12 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
|||||||
public class TemporaryVariable {
|
public class TemporaryVariable {
|
||||||
|
|
||||||
/*package*/ static TemporaryVariable create(@NotNull JsName temporaryName, @Nullable JsExpression initExpression) {
|
/*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
|
@Nullable
|
||||||
|
|||||||
+1
-2
@@ -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.Namer;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator;
|
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.general.Translation;
|
||||||
|
import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
|
||||||
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
|
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
|
||||||
import org.jetbrains.kotlin.js.translate.operation.BinaryOperationTranslator;
|
import org.jetbrains.kotlin.js.translate.operation.BinaryOperationTranslator;
|
||||||
import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator;
|
import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator;
|
||||||
|
|||||||
+32
-18
@@ -16,14 +16,13 @@
|
|||||||
|
|
||||||
@file:JvmName("LoopTranslator")
|
@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 com.google.dart.compiler.backend.js.ast.*
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable
|
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
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.general.Translation
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.CompositeFIF
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.CompositeFIF
|
||||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getHasNextCallable
|
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.JsAstUtils.*
|
||||||
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getLoopParameter
|
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.PsiUtils.getLoopRange
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TemporariesUtils.temporariesInitialization
|
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||||
@@ -117,16 +115,16 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
|||||||
|
|
||||||
val destructuringParameter: KtDestructuringDeclaration? = expression.destructuringParameter
|
val destructuringParameter: KtDestructuringDeclaration? = expression.destructuringParameter
|
||||||
|
|
||||||
fun declareParameter(): JsName {
|
fun declareParameter(): Pair<JsName, Boolean> {
|
||||||
val loopParameter = getLoopParameter(expression)
|
val loopParameter = getLoopParameter(expression)
|
||||||
if (loopParameter != null) {
|
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}" }
|
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? {
|
fun translateBody(itemValue: JsExpression?): JsStatement? {
|
||||||
val realBody = expression.body?.let { Translation.translateAsStatementAndMergeInBlockIfNeeded(it, context) }
|
val realBody = expression.body?.let { Translation.translateAsStatementAndMergeInBlockIfNeeded(it, context) }
|
||||||
@@ -135,10 +133,12 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val currentVarInit =
|
val currentVarInit =
|
||||||
if (destructuringParameter == null)
|
if (destructuringParameter == null) {
|
||||||
newVar(parameterName, itemValue)
|
newVar(parameterName, itemValue)
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
DestructuringDeclarationTranslator.translate(destructuringParameter, parameterName, itemValue, context)
|
DestructuringDeclarationTranslator.translate(destructuringParameter, parameterName, itemValue, context)
|
||||||
|
}
|
||||||
|
|
||||||
if (realBody == null) return JsBlock(currentVarInit)
|
if (realBody == null) return JsBlock(currentVarInit)
|
||||||
|
|
||||||
@@ -170,12 +170,16 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
|||||||
val rangeEnd = context.declareTemporary(rightExpression)
|
val rangeEnd = context.declareTemporary(rightExpression)
|
||||||
|
|
||||||
val body = translateBody(null)
|
val body = translateBody(null)
|
||||||
val initExpression = newVar(parameterName, rangeStart)
|
|
||||||
val conditionExpression = lessThanEq(parameterName.makeRef(), rangeEnd.reference())
|
val conditionExpression = lessThanEq(parameterName.makeRef(), rangeEnd.reference())
|
||||||
val incrementExpression = JsPostfixOperation(JsUnaryOperator.INC, parameterName.makeRef())
|
val incrementExpression = JsPostfixOperation(JsUnaryOperator.INC, parameterName.makeRef())
|
||||||
|
|
||||||
context.addStatementToCurrentBlock(temporariesInitialization(rangeEnd).makeStmt())
|
context.addStatementToCurrentBlock(asSyntheticStatement(rangeEnd.assignmentExpression()))
|
||||||
return JsFor(initExpression, conditionExpression, incrementExpression, body)
|
return if (parameterIsTemporary) {
|
||||||
|
JsFor(assignment(parameterName.makeRef(), rangeStart), conditionExpression, incrementExpression, body)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JsFor(newVar(parameterName, rangeStart), conditionExpression, incrementExpression, body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translateForOverRange(): JsStatement {
|
fun translateForOverRange(): JsStatement {
|
||||||
@@ -188,12 +192,21 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
|||||||
val increment = context.declareTemporary(getProperty("step"))
|
val increment = context.declareTemporary(getProperty("step"))
|
||||||
|
|
||||||
val body = translateBody(null)
|
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())
|
val incrementExpression = addAssign(parameterName.makeRef(), increment.reference())
|
||||||
|
|
||||||
context.addStatementToCurrentBlock(temporariesInitialization(rangeExpression, start, end, increment).makeStmt())
|
context.addStatementToCurrentBlock(asSyntheticStatement(rangeExpression.assignmentExpression()))
|
||||||
return JsFor(initExpression, conditionExpression, incrementExpression, body)
|
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 {
|
fun translateForOverArray(): JsStatement {
|
||||||
@@ -204,11 +217,12 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
|
|||||||
|
|
||||||
val arrayAccess = JsArrayAccess(rangeExpression.reference(), index.reference())
|
val arrayAccess = JsArrayAccess(rangeExpression.reference(), index.reference())
|
||||||
val body = translateBody(arrayAccess)
|
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 conditionExpression = inequality(index.reference(), end.reference())
|
||||||
val incrementExpression = JsPrefixOperation(JsUnaryOperator.INC, index.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)
|
return JsFor(initExpression, conditionExpression, incrementExpression, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.js.translate.expression;
|
package org.jetbrains.kotlin.js.translate.expression;
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
||||||
@@ -57,9 +58,12 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
KtExpression subject = expression.getSubjectExpression();
|
KtExpression subject = expression.getSubjectExpression();
|
||||||
if (subject != null) {
|
if (subject != null) {
|
||||||
JsExpression subjectExpression = Translation.translateAsExpression(subject, context);
|
JsExpression subjectExpression = Translation.translateAsExpression(subject, context);
|
||||||
if (TranslationUtils.isCacheNeeded(subjectExpression)) {
|
if (!JsAstUtils.isEmptyExpression(subjectExpression)) {
|
||||||
TemporaryVariable subjectVar = context.declareTemporary(null);
|
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();
|
subjectExpression = subjectVar.reference();
|
||||||
}
|
}
|
||||||
expressionToMatch = subjectExpression;
|
expressionToMatch = subjectExpression;
|
||||||
|
|||||||
@@ -302,6 +302,12 @@ public final class JsAstUtils {
|
|||||||
return new JsBinaryOperation(JsBinaryOperator.ASG, left, right);
|
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
|
@Nullable
|
||||||
public static Pair<JsExpression, JsExpression> decomposeAssignment(@NotNull JsExpression expr) {
|
public static Pair<JsExpression, JsExpression> decomposeAssignment(@NotNull JsExpression expr) {
|
||||||
if (!(expr instanceof JsBinaryOperation)) return null;
|
if (!(expr instanceof JsBinaryOperation)) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user