JS backend: don't use the temporary variables in SafeCall and SureCall when is not necessary.

For example:
val a : A? = null
a!!
a?.foo()

translated before:
var a = null;
var tmp$0, tmp$1;
(tmp$0 = a) != null ? tmp$0 : Kotlin.throwNPE();
(tmp$1 = a) != null ? tmp$1.foo() : null;

translated after:
var a = null;
a != null ? a : Kotlin.throwNPE();
a != null ? a.foo() : null;
This commit is contained in:
develar
2013-07-19 15:51:03 +04:00
committed by Zalim Bashorov
parent 94152da97b
commit 78945a9461
5 changed files with 47 additions and 20 deletions
@@ -156,8 +156,8 @@ public final class Namer {
} }
@NotNull @NotNull
public JsExpression throwNPEFunctionCall() { public JsExpression throwNPEFunctionRef() {
return new JsInvocation(new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject())); return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
} }
@NotNull @NotNull
@@ -311,6 +311,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull @NotNull
public JsNode visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, public JsNode visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
// KT-2670
// we actually do not care for types in js // we actually do not care for types in js
return Translation.translateExpression(expression.getLeft(), context); return Translation.translateExpression(expression.getLeft(), context);
} }
@@ -16,12 +16,10 @@
package org.jetbrains.k2js.translate.operation; package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsConditional;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetUnaryExpression; import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.reference.CallBuilder; import org.jetbrains.k2js.translate.reference.CallBuilder;
import org.jetbrains.k2js.translate.reference.CallType; import org.jetbrains.k2js.translate.reference.CallType;
@@ -33,8 +31,7 @@ import static org.jetbrains.k2js.translate.general.Translation.translateAsExpres
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall; import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression; import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNotNullCheck; import static org.jetbrains.k2js.translate.utils.TranslationUtils.sure;
public final class UnaryOperationTranslator { public final class UnaryOperationTranslator {
private UnaryOperationTranslator() { private UnaryOperationTranslator() {
@@ -58,14 +55,7 @@ public final class UnaryOperationTranslator {
@NotNull @NotNull
private static JsExpression translateExclExclOperator(@NotNull JetUnaryExpression expression, @NotNull TranslationContext context) { private static JsExpression translateExclExclOperator(@NotNull JetUnaryExpression expression, @NotNull TranslationContext context) {
JsExpression translatedExpression = translateAsExpression(getBaseExpression(expression), context); return sure(translateAsExpression(getBaseExpression(expression), context), context);
TemporaryConstVariable tempVar = context.getOrDeclareTemporaryConstVariable(translatedExpression);
JsConditional ensureNotNull = new JsConditional(isNotNullCheck(tempVar.value()), tempVar.value(), context.namer().throwNPEFunctionCall());
// associate (cache) ensureNotNull expression to new LazyValue with same name.
context.associateExpressionToLazyValue(ensureNotNull, new TemporaryConstVariable(tempVar.name(), ensureNotNull));
return ensureNotNull;
} }
@NotNull @NotNull
@@ -24,10 +24,9 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression; import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression;
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNotNullCheck; import static org.jetbrains.k2js.translate.utils.TranslationUtils.notNullConditional;
public enum CallType { public enum CallType {
SAFE { SAFE {
@@ -36,9 +35,9 @@ public enum CallType {
JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor, JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
assert receiver != null; assert receiver != null;
JsConditional expression = notNullConditional(receiver, JsLiteral.NULL, context);
TemporaryConstVariable tempVar = context.getOrDeclareTemporaryConstVariable(receiver); expression.setThenExpression(constructor.construct(expression.getThenExpression()));
return new JsConditional(isNotNullCheck(tempVar.value()), constructor.construct(tempVar.value()), JsLiteral.NULL); return expression;
} }
}, },
//TODO: bang qualifier is not implemented in frontend for now //TODO: bang qualifier is not implemented in frontend for now
@@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.Translation;
@@ -75,7 +76,28 @@ public final class TranslationUtils {
JsBinaryOperator operator = isNegated ? JsBinaryOperator.NEQ : JsBinaryOperator.EQ; JsBinaryOperator operator = isNegated ? JsBinaryOperator.NEQ : JsBinaryOperator.EQ;
return new JsBinaryOperation(operator, expressionToCheck, JsLiteral.NULL); return new JsBinaryOperation(operator, expressionToCheck, JsLiteral.NULL);
} }
@NotNull
public static JsConditional notNullConditional(
@NotNull JsExpression expression,
@NotNull JsExpression elseExpression,
@NotNull TranslationContext context
) {
JsExpression testExpression;
JsExpression thenExpression;
if (isCacheNeeded(expression)) {
TemporaryConstVariable tempVar = context.getOrDeclareTemporaryConstVariable(expression);
testExpression = isNotNullCheck(tempVar.value());
thenExpression = tempVar.value();
}
else {
testExpression = isNotNullCheck(expression);
thenExpression = expression;
}
return new JsConditional(testExpression, thenExpression, elseExpression);
}
@NotNull @NotNull
public static List<JsExpression> translateArgumentList(@NotNull TranslationContext context, public static List<JsExpression> translateArgumentList(@NotNull TranslationContext context,
@NotNull List<? extends ValueArgument> jetArguments) { @NotNull List<? extends ValueArgument> jetArguments) {
@@ -189,4 +211,19 @@ public final class TranslationUtils {
return Pair.create(null, expression); return Pair.create(null, expression);
} }
} }
@NotNull
public static JsConditional sure(@NotNull JsExpression expression, @NotNull TranslationContext context) {
JsInvocation throwNPE = new JsInvocation(context.namer().throwNPEFunctionRef());
JsConditional ensureNotNull = notNullConditional(expression, throwNPE, context);
JsExpression thenExpression = ensureNotNull.getThenExpression();
if (thenExpression instanceof JsNameRef) {
// associate (cache) ensureNotNull expression to new TemporaryConstVariable with same name.
context.associateExpressionToLazyValue(ensureNotNull,
new TemporaryConstVariable(((JsNameRef) thenExpression).getName(), ensureNotNull));
}
return ensureNotNull;
}
} }