From 78945a94614461d2d74a775144253dda817d9cda Mon Sep 17 00:00:00 2001 From: develar Date: Fri, 19 Jul 2013 15:51:03 +0400 Subject: [PATCH] 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; --- .../k2js/translate/context/Namer.java | 4 +- .../expression/ExpressionVisitor.java | 1 + .../operation/UnaryOperationTranslator.java | 14 +------ .../k2js/translate/reference/CallType.java | 9 ++--- .../translate/utils/TranslationUtils.java | 39 ++++++++++++++++++- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java index 443c2293a2b..ff936ef94fe 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java @@ -156,8 +156,8 @@ public final class Namer { } @NotNull - public JsExpression throwNPEFunctionCall() { - return new JsInvocation(new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject())); + public JsExpression throwNPEFunctionRef() { + return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject()); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index a3bc1f69eec..b366416ebed 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -311,6 +311,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, @NotNull TranslationContext context) { + // KT-2670 // we actually do not care for types in js return Translation.translateExpression(expression.getLeft(), context); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java index 85a82e04267..fb28a1c94c9 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/operation/UnaryOperationTranslator.java @@ -16,12 +16,10 @@ 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 org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetUnaryExpression; 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.reference.CallBuilder; 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.PsiUtils.getBaseExpression; 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 { private UnaryOperationTranslator() { @@ -58,14 +55,7 @@ public final class UnaryOperationTranslator { @NotNull private static JsExpression translateExclExclOperator(@NotNull JetUnaryExpression expression, @NotNull TranslationContext context) { - JsExpression translatedExpression = translateAsExpression(getBaseExpression(expression), 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; + return sure(translateAsExpression(getBaseExpression(expression), context), context); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java index 893455b6d3c..dc74b50d81b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallType.java @@ -24,10 +24,9 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression; import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression; -import org.jetbrains.k2js.translate.context.TemporaryConstVariable; 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 { SAFE { @@ -36,9 +35,9 @@ public enum CallType { JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor, @NotNull TranslationContext context) { assert receiver != null; - - TemporaryConstVariable tempVar = context.getOrDeclareTemporaryConstVariable(receiver); - return new JsConditional(isNotNullCheck(tempVar.value()), constructor.construct(tempVar.value()), JsLiteral.NULL); + JsConditional expression = notNullConditional(receiver, JsLiteral.NULL, context); + expression.setThenExpression(constructor.construct(expression.getThenExpression())); + return expression; } }, //TODO: bang qualifier is not implemented in frontend for now diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index 5a200ca1e8d..ce8e9f754b2 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor; 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.general.Translation; @@ -75,7 +76,28 @@ public final class TranslationUtils { JsBinaryOperator operator = isNegated ? JsBinaryOperator.NEQ : JsBinaryOperator.EQ; 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 public static List translateArgumentList(@NotNull TranslationContext context, @NotNull List jetArguments) { @@ -189,4 +211,19 @@ public final class TranslationUtils { 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; + } }