JS/Inlining: change sideEffects metadata to take three values: producing side effect, dependding on side effect and purity

This commit is contained in:
Alexey Andreev
2016-06-02 17:41:17 +03:00
parent 774efa4e70
commit 6b99d4e1c5
26 changed files with 154 additions and 92 deletions
@@ -55,7 +55,7 @@ var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = nul
var HasMetadata.synthetic: Boolean by MetadataProperty(default = false)
var HasMetadata.sideEffects: Boolean by MetadataProperty(default = true)
var HasMetadata.sideEffects: SideEffectKind by MetadataProperty(default = SideEffectKind.AFFECTS_STATE)
enum class TypeCheck {
TYPEOF,
@@ -64,3 +64,9 @@ enum class TypeCheck {
IS_ANY,
AND_PREDICATE
}
enum class SideEffectKind {
AFFECTS_STATE,
DEPENDS_ON_STATE,
PURE
}
@@ -17,10 +17,7 @@
package org.jetbrains.kotlin.js.inline
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import com.google.dart.compiler.backend.js.ast.metadata.*
import com.intellij.util.SmartList
import org.jetbrains.kotlin.js.inline.util.IdentitySet
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
@@ -270,7 +267,7 @@ internal class ExpressionDecomposer private constructor(
// Qualifier might be a reference to lambda property. See KT-7674
// An exception here is `fn.call()`, which are marked as side effect free. Further recognition of such
// case in inliner might be quite difficult, so never extract such call (and other calls marked this way).
if (qualifier in containsNodeWithSideEffect && (qualifier as? HasMetadata)?.sideEffects ?: true) {
if (qualifier in containsNodeWithSideEffect && (qualifier as? HasMetadata)?.sideEffects != SideEffectKind.PURE) {
qualifier = qualifier.extractToTemporary()
}
else if (callee != null && receiver != null && receiver in containsNodeWithSideEffect) {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.inline.clean
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.collectLocalVariables
@@ -53,7 +54,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
if (expression.name in localVars) {
listOf()
}
else if (!expression.sideEffects) {
else if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
val qualifier = expression.qualifier
if (qualifier != null) replace(qualifier) else listOf()
}
@@ -78,7 +79,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
}
is JsBinaryOperation -> {
if (expression.sideEffects) {
if (expression.sideEffects == SideEffectKind.AFFECTS_STATE) {
when (expression.operator) {
JsBinaryOperator.BIT_AND,
JsBinaryOperator.BIT_OR,
@@ -130,7 +131,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
}
is JsInvocation -> {
if (!expression.sideEffects) {
if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
replace(expression.qualifier) + replaceMany(expression.arguments)
}
else {
@@ -139,7 +140,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
}
is JsNew -> {
if (!expression.sideEffects) {
if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
replace(expression.constructorExpression) + replaceMany(expression.arguments)
}
else {
@@ -166,7 +167,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
// Then, inlined body of `bar` never uses `$tmp`, therefore we can eliminate it, so `Kotlin.modules['foo']` remains.
// It's good to eliminate such useless expression.
is JsArrayAccess -> {
if (!expression.sideEffects) {
if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
replace(expression.arrayExpression) + replace(expression.indexExpression)
}
else {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.inline.clean
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
@@ -180,14 +181,14 @@ internal class TemporaryVariableElimination(function: JsFunction) {
}
super.visitNameRef(nameRef)
if (nameRef.qualifier != null && nameRef.sideEffects) {
if (nameRef.qualifier != null && nameRef.sideEffects == SideEffectKind.AFFECTS_STATE) {
sideEffectOccurred = true
}
}
override fun visitInvocation(invocation: JsInvocation) {
super.visitInvocation(invocation)
if (invocation.sideEffects) {
if (invocation.sideEffects == SideEffectKind.AFFECTS_STATE) {
sideEffectOccurred = true
}
}
@@ -242,7 +243,7 @@ internal class TemporaryVariableElimination(function: JsFunction) {
override fun visitArrayAccess(x: JsArrayAccess) {
super.visitArrayAccess(x)
if (x.sideEffects) {
if (x.sideEffects == SideEffectKind.AFFECTS_STATE) {
sideEffectOccurred = true
}
}
@@ -533,15 +534,21 @@ internal class TemporaryVariableElimination(function: JsFunction) {
private fun isTrivial(expr: JsExpression): Boolean = when (expr) {
is JsNameRef -> {
val name = expr.name
name in namesToProcess && when (definitions[name]) {
null, 0 -> true
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false
else -> false
val qualifier = expr.qualifier
if (expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier))) {
true
}
else {
val name = expr.name
name in namesToProcess && when (definitions[name]) {
null, 0 -> true
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false
else -> false
}
}
}
is JsLiteral.JsValueLiteral -> true
is JsInvocation -> !expr.sideEffects && isTrivial(expr.qualifier) && expr.arguments.all { isTrivial(it) }
is JsInvocation -> expr.sideEffects == SideEffectKind.PURE && isTrivial(expr.qualifier) && expr.arguments.all { isTrivial(it) }
is JsArrayAccess -> isTrivial(expr.arrayExpression) && isTrivial(expr.indexExpression)
else -> false
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.inline.util
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.any
@@ -28,7 +29,7 @@ fun JsExpression.canHaveOwnSideEffect(vars: Set<JsName>) = when (this) {
is JsConditional,
is JsLiteral -> false
is JsBinaryOperation -> operator.isAssignment
is JsNameRef -> name !in vars && sideEffects
is HasMetadata -> sideEffects
is JsNameRef -> name !in vars && sideEffects != SideEffectKind.PURE
is HasMetadata -> sideEffects != SideEffectKind.PURE
else -> true
}
@@ -257,6 +257,18 @@ public class InlineEvaluationOrderTestGenerated extends AbstractInlineEvaluation
doTest(fileName);
}
@TestMetadata("propertyAccessAfterModification.kt")
public void testPropertyAccessAfterModification() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAfterModification.kt");
doTest(fileName);
}
@TestMetadata("propertyAccessAndInitializer.kt")
public void testPropertyAccessAndInitializer() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAndInitializer.kt");
doTest(fileName);
}
@TestMetadata("propertyAccessWithSideEffect.kt")
public void testPropertyAccessWithSideEffect() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessWithSideEffect.kt");
@@ -20,6 +20,7 @@ import com.google.dart.compiler.backend.js.ast.JsEmptyExpression
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.metadata.HasMetadata
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -76,7 +77,7 @@ fun VariableAccessInfo.constructAccessExpression(ref: JsExpression): JsExpressio
return ref
} else {
return if (value !is JsEmptyExpression) {
(ref as? HasMetadata)?.let { it.sideEffects = false }
(ref as? HasMetadata)?.let { it.sideEffects = SideEffectKind.PURE }
JsAstUtils.assignment(ref, value!!)
}
else {
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.js.translate.operation.OperatorTable
import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.PsiUtils
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -59,7 +59,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
if (isNative && hasSpreadOperator) {
return nativeSpreadFunWithDispatchOrExtensionReceiver(argumentsInfo, functionName)
}
return JsInvocation(fqnWithoutSideEffects(functionName, dispatchReceiver), argumentsInfo.translateArguments)
return JsInvocation(pureFqn(functionName, dispatchReceiver), argumentsInfo.translateArguments)
}
fun buildDefaultCallWithoutReceiver(context: TranslationContext,
@@ -78,7 +78,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
val functionRef = context.aliasOrValue(callableDescriptor) {
val qualifierForFunction = context.getQualifierForDescriptor(it)
fqnWithoutSideEffects(functionName, qualifierForFunction)
pureFqn(functionName, qualifierForFunction)
}
return JsInvocation(functionRef, argumentsInfo.translateArguments)
}
@@ -101,7 +101,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
val functionRef = context.aliasOrValue(callableDescriptor) {
val qualifierForFunction = context.getQualifierForDescriptor(it)
fqnWithoutSideEffects(functionName, qualifierForFunction) // TODO: remake to call
pureFqn(functionName, qualifierForFunction) // TODO: remake to call
}
val referenceToCall =
@@ -238,7 +238,7 @@ object SuperCallCase : FunctionCallCase() {
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
// TODO: spread operator
val prototypeClass = fqnWithoutSideEffects(Namer.getPrototypeName(), calleeOwner)
val prototypeClass = pureFqn(Namer.getPrototypeName(), calleeOwner)
val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass))
return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!))
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.callTranslator
import com.google.dart.compiler.backend.js.ast.JsExpression
import com.google.dart.compiler.backend.js.ast.JsInvocation
import com.google.dart.compiler.backend.js.ast.JsNameRef
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -74,8 +75,8 @@ object DefaultVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
val accessor = JsNameRef(variableName, dispatchReceiver!!)
val descriptor = callableDescriptor
if (descriptor is PropertyDescriptor && JsDescriptorUtils.sideEffectsPossible(descriptor)) {
accessor.sideEffects = false
if (descriptor is PropertyDescriptor && !JsDescriptorUtils.sideEffectsPossible(descriptor)) {
accessor.sideEffects = SideEffectKind.DEPENDS_ON_STATE
}
return constructAccessExpression(accessor)
}
@@ -17,13 +17,12 @@
package org.jetbrains.kotlin.js.translate.context;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
@@ -38,7 +37,7 @@ import java.util.Collections;
import java.util.List;
import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
@@ -143,7 +142,7 @@ public final class Namer {
@NotNull
public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) {
return fqnWithoutSideEffects(SUPER_METHOD_NAME, superClassJsName.makeRef());
return pureFqn(SUPER_METHOD_NAME, superClassJsName.makeRef());
}
@NotNull
@@ -182,7 +181,7 @@ public final class Namer {
@NotNull
public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
return fqnWithoutSideEffects(getPrototypeName(), classOrTraitExpression);
return pureFqn(getPrototypeName(), classOrTraitExpression);
}
@NotNull
@@ -207,12 +206,12 @@ public final class Namer {
@NotNull
public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
return fqnWithoutSideEffects(CALL_FUNCTION, functionExpression);
return pureFqn(CALL_FUNCTION, functionExpression);
}
@NotNull
public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) {
return fqnWithoutSideEffects(APPLY_FUNCTION, functionExpression);
return pureFqn(APPLY_FUNCTION, functionExpression);
}
@NotNull
@@ -222,7 +221,7 @@ public final class Namer {
@NotNull
public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) {
return fqnWithoutSideEffects(CAPTURED_VAR_FIELD, ref);
return pureFqn(CAPTURED_VAR_FIELD, ref);
}
@NotNull
@@ -297,7 +296,6 @@ public final class Namer {
isTypeName = kotlinScope.declareName("isType");
modulesMap = kotlin("modules");
MetadataProperties.setSideEffects((HasMetadata) modulesMap, false);
}
@NotNull
@@ -377,7 +375,7 @@ public final class Namer {
@NotNull
public static JsNameRef kotlin(@NotNull JsName name) {
return fqnWithoutSideEffects(name, kotlinObject());
return pureFqn(name, kotlinObject());
}
@NotNull
@@ -387,7 +385,7 @@ public final class Namer {
@NotNull
public static JsNameRef kotlinObject() {
return fqnWithoutSideEffects(KOTLIN_NAME, null);
return pureFqn(KOTLIN_NAME, null);
}
@NotNull
@@ -444,14 +442,14 @@ public final class Namer {
JsInvocation invocation = new JsInvocation(kotlin(functionName));
invocation.getArguments().addAll(arguments);
MetadataProperties.setTypeCheck(invocation, metadata);
MetadataProperties.setSideEffects(invocation, false);
MetadataProperties.setSideEffects(invocation, SideEffectKind.PURE);
return invocation;
}
@NotNull
public JsExpression isInstanceOf(@NotNull JsExpression instance, @NotNull JsExpression type) {
JsInvocation result = new JsInvocation(kotlin(isTypeName), instance, type);
MetadataProperties.setSideEffects(result, false);
MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result;
}
@@ -501,16 +499,16 @@ public final class Namer {
@NotNull
public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) {
JsArrayAccess result = new JsArrayAccess(modulesMap, moduleName);
MetadataProperties.setSideEffects(result, false);
MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result;
}
public static JsNameRef kotlinLong() {
return fqnWithoutSideEffects("Long", kotlinObject());
return pureFqn("Long", kotlinObject());
}
@NotNull
public static JsNameRef createInlineFunction() {
return fqnWithoutSideEffects(DEFINE_INLINE_FUNCTION, kotlinObject());
return pureFqn(DEFINE_INLINE_FUNCTION, kotlinObject());
}
}
@@ -21,6 +21,7 @@ import com.google.common.collect.Maps;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import com.intellij.openapi.util.Factory;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
@@ -45,7 +46,7 @@ import java.util.Map;
import java.util.Set;
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
@@ -196,7 +197,7 @@ public final class StaticContext {
@NotNull
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
JsName packageName = getNameForPackage(packageFqName);
return fqnWithoutSideEffects(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent()));
return pureFqn(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent()));
}
@NotNull
@@ -225,7 +226,7 @@ public final class StaticContext {
FqName fqName = packageFqName;
while (true) {
JsNameRef ref = fqnWithoutSideEffects(getNameForPackage(fqName), null);
JsNameRef ref = pureFqn(getNameForPackage(fqName), null);
if (qualifier == null) {
result = ref;
@@ -640,7 +641,7 @@ public final class StaticContext {
descriptor instanceof PackageFragmentDescriptor ||
descriptor instanceof ClassDescriptor
) {
MetadataProperties.setSideEffects((HasMetadata) expression, false);
MetadataProperties.setSideEffects((HasMetadata) expression, SideEffectKind.PURE);
}
}
return expression;
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import com.intellij.util.SmartList
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.bridges.Bridge
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.js.translate.context.Namer.getReceiverParameterName
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference
@@ -168,8 +168,7 @@ private class PropertyTranslator(
val fakeArgumentExpression =
(delegatedCall.valueArgumentsByIndex!![1] as ExpressionValueArgument).valueArgument!!.getArgumentExpression()
return context.innerContextWithAliasesForExpressions(mapOf(
fakeArgumentExpression to JsNew(fqnWithoutSideEffects("PropertyMetadata", Namer.kotlinObject()),
listOf(propertyNameLiteral))
fakeArgumentExpression to JsNew(pureFqn("PropertyMetadata", Namer.kotlinObject()), listOf(propertyNameLiteral))
))
}
@@ -17,10 +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.functionDescriptor
import com.google.dart.compiler.backend.js.ast.metadata.isLocal
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
import com.google.dart.compiler.backend.js.ast.metadata.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
import org.jetbrains.kotlin.js.translate.context.TranslationContext
@@ -63,13 +60,13 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
}
lambda.isLocal = true
return invokingContext.define(descriptor, lambda).apply { sideEffects = false }
return invokingContext.define(descriptor, lambda).apply { sideEffects = SideEffectKind.PURE }
}
}
fun JsFunction.withCapturedParameters(context: TranslationContext, invokingContext: TranslationContext, descriptor: MemberDescriptor): JsExpression {
val ref = invokingContext.define(descriptor, this).apply { sideEffects = false }
val invocation = JsInvocation(ref).apply { sideEffects = false }
val ref = invokingContext.define(descriptor, this).apply { sideEffects = SideEffectKind.PURE }
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
val invocationArguments = invocation.arguments
val functionParameters = this.parameters
@@ -43,7 +43,7 @@ import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.setDefaultValueForArguments;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getPrimaryConstructorParameters;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType;
@@ -124,8 +124,8 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
initFunction.getParameters().add(0, new JsParameter(outerName));
JsExpression paramRef = fqnWithoutSideEffects(outerName, null);
JsExpression assignment = JsAstUtils.assignment(fqnWithoutSideEffects(outerName, JsLiteral.THIS), paramRef);
JsExpression paramRef = pureFqn(outerName, null);
JsExpression assignment = JsAstUtils.assignment(pureFqn(outerName, JsLiteral.THIS), paramRef);
initFunction.getBody().getStatements().add(new JsExpressionStatement(assignment));
}
@@ -178,7 +178,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
}
if (superDescriptor.getContainingDeclaration().isInner() && descriptor.isInner()) {
arguments.add(fqnWithoutSideEffects(Namer.OUTER_FIELD_NAME, JsLiteral.THIS));
arguments.add(pureFqn(Namer.OUTER_FIELD_NAME, JsLiteral.THIS));
}
if (!DescriptorUtils.isAnonymousObject(descriptor)) {
@@ -25,8 +25,6 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic {
@NotNull
@@ -44,6 +42,6 @@ public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic {
@NotNull TranslationContext context
) {
assert receiver != null;
return new JsInvocation(fqnWithoutSideEffects(functionName, receiver), arguments);
return new JsInvocation(JsAstUtils.pureFqn(functionName, receiver), arguments);
}
}
@@ -24,8 +24,6 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
//TODO: find should be usages
public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic {
@@ -42,6 +40,6 @@ public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic {
@NotNull TranslationContext context) {
assert receiver != null;
assert arguments.isEmpty() : "Properties can't have arguments.";
return fqnWithoutSideEffects(propertyName, receiver);
return JsAstUtils.pureFqn(propertyName, receiver);
}
}
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories;
import com.google.common.collect.Lists;
import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -97,9 +96,7 @@ public final class ArrayFIF extends CompositeFIF {
assert receiver != null;
assert arguments.size() == 1 : "Array get expression must have one argument.";
JsExpression indexExpression = arguments.get(0);
JsArrayAccess result = new JsArrayAccess(receiver, indexExpression);
MetadataProperties.setSideEffects(result, false);
return result;
return new JsArrayAccess(receiver, indexExpression);
}
};
@@ -43,7 +43,7 @@ public class KotlinFunctionIntrinsic extends FunctionIntrinsic {
@NotNull List<JsExpression> arguments,
@NotNull TranslationContext context
) {
JsExpression function = JsAstUtils.fqnWithoutSideEffects(functionName, Namer.kotlinObject());
JsExpression function = JsAstUtils.pureFqn(functionName, Namer.kotlinObject());
return new JsInvocation(function, receiver == null ? arguments : TranslationUtils.generateInvocationArguments(receiver, arguments));
}
}
@@ -211,7 +211,7 @@ public final class TopLevelFIF extends CompositeFIF {
String mangledName = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getMutableMap(), operationName());
return new JsInvocation(JsAstUtils.fqnWithoutSideEffects(mangledName, thisOrReceiver), arguments);
return new JsInvocation(JsAstUtils.pureFqn(mangledName, thisOrReceiver), arguments);
}
}
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.js.translate.reference
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.js.translate.context.Namer
@@ -143,7 +145,7 @@ class CallArgumentTranslator private constructor(
concatArguments!!.addAll(result)
if (!argsBeforeVararg!!.isEmpty()) {
concatArguments.add(0, JsArrayLiteral(argsBeforeVararg))
concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
}
result = SmartList(concatArgumentsIfNeeded(concatArguments))
@@ -212,7 +214,7 @@ class CallArgumentTranslator private constructor(
context: TranslationContext, shouldWrapVarargInArray: Boolean): ArgumentsKind {
if (arguments.isEmpty()) {
if (shouldWrapVarargInArray) {
result.add(JsArrayLiteral(listOf<JsExpression>()))
result.add(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
}
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
}
@@ -289,7 +291,7 @@ class CallArgumentTranslator private constructor(
if (valueArgument.getSpreadElement() != null) {
if (lastArrayContent.size > 0) {
concatArguments.add(JsArrayLiteral(lastArrayContent))
concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
concatArguments.add(expressionArgument)
lastArrayContent = SmartList<JsExpression>()
}
@@ -302,7 +304,7 @@ class CallArgumentTranslator private constructor(
}
}
if (lastArrayContent.size > 0) {
concatArguments.add(JsArrayLiteral(lastArrayContent))
concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
}
return concatArguments
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.translate.utils;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import com.intellij.util.SmartList;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
@@ -32,12 +33,12 @@ import java.util.Collections;
import java.util.List;
public final class JsAstUtils {
private static final JsNameRef DEFINE_PROPERTY = fqnWithoutSideEffects("defineProperty", null);
public static final JsNameRef CREATE_OBJECT = fqnWithoutSideEffects("create", null);
private static final JsNameRef DEFINE_PROPERTY = pureFqn("defineProperty", null);
public static final JsNameRef CREATE_OBJECT = pureFqn("create", null);
private static final JsNameRef VALUE = new JsNameRef("value");
private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(fqnWithoutSideEffects("writable", null), JsLiteral.TRUE);
private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(fqnWithoutSideEffects("enumerable", null), JsLiteral.TRUE);
private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(pureFqn("writable", null), JsLiteral.TRUE);
private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(pureFqn("enumerable", null), JsLiteral.TRUE);
public static final String LENDS_JS_DOC_TAG = "lends";
@@ -128,7 +129,7 @@ public final class JsAstUtils {
@NotNull
public static JsInvocation invokeMethod(@NotNull JsExpression thisObject, @NotNull String name, @NotNull JsExpression... arguments) {
return new JsInvocation(fqnWithoutSideEffects(name, thisObject), arguments);
return new JsInvocation(pureFqn(name, thisObject), arguments);
}
@NotNull
@@ -173,7 +174,7 @@ public final class JsAstUtils {
@NotNull
private static JsExpression rangeTo(@NotNull String rangeClassName, @NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) {
JsNameRef expr = fqnWithoutSideEffects(rangeClassName, Namer.kotlinObject());
JsNameRef expr = pureFqn(rangeClassName, Namer.kotlinObject());
JsNew numberRangeConstructorInvocation = new JsNew(expr);
setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd);
return numberRangeConstructorInvocation;
@@ -488,16 +489,16 @@ public final class JsAstUtils {
}
@NotNull
public static JsNameRef fqnWithoutSideEffects(@NotNull String identifier, @Nullable JsExpression qualifier) {
public static JsNameRef pureFqn(@NotNull String identifier, @Nullable JsExpression qualifier) {
JsNameRef result = new JsNameRef(identifier, qualifier);
MetadataProperties.setSideEffects(result, false);
MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result;
}
@NotNull
public static JsNameRef fqnWithoutSideEffects(@NotNull JsName identifier, @Nullable JsExpression qualifier) {
public static JsNameRef pureFqn(@NotNull JsName identifier, @Nullable JsExpression qualifier) {
JsNameRef result = new JsNameRef(identifier, qualifier);
MetadataProperties.setSideEffects(result, false);
MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result;
}
@@ -148,7 +148,13 @@ public final class JsDescriptorUtils {
}
public static boolean sideEffectsPossible(@NotNull PropertyDescriptor property) {
return isDefaultAccessor(property.getGetter()) && !ModalityKt.isOverridableOrOverrides(property);
return !isDefaultAccessor(property.getGetter()) || ModalityKt.isOverridableOrOverrides(property) ||
isStaticInitializationPossible(property);
}
private static boolean isStaticInitializationPossible(PropertyDescriptor property) {
DeclarationDescriptor container = property.getContainingDeclaration();
return container instanceof PackageFragmentDescriptor || DescriptorUtils.isObject(container);
}
public static boolean isSimpleFinalProperty(@NotNull PropertyDescriptor propertyDescriptor) {
@@ -0,0 +1,16 @@
package foo
class A {
var x = 23
}
inline fun bar(value: Int, a: A): Int {
a.x = 42
return value
}
fun box(): String {
val a = A()
assertEquals(23, bar(a.x, a))
return "OK"
}
@@ -0,0 +1,21 @@
package foo
object A {
init {
log("A.init")
}
val x = 23
}
inline fun bar(value: Int) {
log("bar->begin")
log("value=$value")
log("bar->end")
}
fun box(): String {
bar(A.x)
assertEquals("A.init;bar->begin;value=23;bar->end;", pullLog())
return "OK"
}
@@ -1,7 +1,7 @@
package foo
// CHECK_CONTAINS_NO_CALLS: test
// CHECK_VARS_COUNT: function=test count=1
// CHECK_VARS_COUNT: function=test count=0
object SumHolder {
var sum = 0