diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 8a0e59968e6..dd396ecc380 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2601,7 +2601,9 @@ public class ExpressionCodegen extends JetVisitor implem } private void generateExpressionWithNullFallback(@NotNull JetExpression expression, @NotNull Label ifnull) { + expression = JetPsiUtil.deparenthesize(expression); Type type = expressionType(expression); + if (expression instanceof JetSafeQualifiedExpression && !isPrimitive(type)) { StackValue value = generateSafeQualifiedExpression((JetSafeQualifiedExpression) expression, ifnull); value.put(type, v); @@ -2612,11 +2614,10 @@ public class ExpressionCodegen extends JetVisitor implem } private StackValue generateSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, @NotNull Label ifnull) { - JetExpression receiver = JetPsiUtil.deparenthesize(expression.getReceiverExpression()); + JetExpression receiver = expression.getReceiverExpression(); JetExpression selector = expression.getSelectorExpression(); Type receiverType = expressionType(receiver); - assert receiver != null : "receiver should be not null: " + expression.getText(); generateExpressionWithNullFallback(receiver, ifnull); if (isPrimitive(receiverType)) { @@ -2631,13 +2632,14 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, StackValue unused) { Label ifnull = new Label(); - Label end = new Label(); Type type = boxType(expressionType(expression)); StackValue value = generateSafeQualifiedExpression(expression, ifnull); value.put(type, v); if (!isPrimitive(expressionType(expression.getReceiverExpression()))) { + Label end = new Label(); + v.goTo(end); v.mark(ifnull); v.pop(); @@ -2845,13 +2847,13 @@ public class ExpressionCodegen extends JetVisitor implem } private StackValue generateElvis(JetBinaryExpression expression) { - JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); + JetExpression left = expression.getLeft(); Type exprType = expressionType(expression); Type leftType = expressionType(left); Label ifNull = new Label(); - Label end = new Label(); + assert left != null : "left expression in elvis should be not null: " + expression.getText(); generateExpressionWithNullFallback(left, ifNull); @@ -2864,6 +2866,8 @@ public class ExpressionCodegen extends JetVisitor implem v.ifnull(ifNull); StackValue.onStack(leftType).put(exprType, v); + + Label end = new Label(); v.goTo(end); v.mark(ifNull); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java index c8670d2d5e3..c02f1e591ca 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxedBasicValue.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.codegen.optimization.boxing; +import org.jetbrains.jet.codegen.AsmUtil; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; @@ -28,12 +29,12 @@ import java.util.Set; public class BoxedBasicValue extends BasicValue { private final Set associatedInsns = new HashSet(); private final AbstractInsnNode boxingInsn; - private final Type boxedType; + private final Type primitiveType; private boolean wasUnboxed = false; - public BoxedBasicValue(Type type, Type boxedType, AbstractInsnNode insnNode) { - super(type); - this.boxedType = boxedType; + public BoxedBasicValue(Type primitiveType, AbstractInsnNode insnNode) { + super(AsmUtil.boxType(primitiveType)); + this.primitiveType = primitiveType; associatedInsns.add(insnNode); boxingInsn = insnNode; } @@ -58,8 +59,8 @@ public class BoxedBasicValue extends BasicValue { associatedInsns.add(insnNode); } - public Type getBoxedType() { - return boxedType; + public Type getPrimitiveType() { + return primitiveType; } public boolean wasUnboxed() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java index a131b98b61d..271acfc47fa 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/BoxingInterpreter.java @@ -16,10 +16,14 @@ package org.jetbrains.jet.codegen.optimization.boxing; +import com.google.common.collect.ImmutableSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.AsmUtil; import org.jetbrains.jet.codegen.optimization.common.OptimizationBasicInterpreter; +import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; import org.jetbrains.org.objectweb.asm.Opcodes; +import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; import org.jetbrains.org.objectweb.asm.tree.InsnList; import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode; @@ -31,6 +35,18 @@ import java.util.List; import java.util.Map; public class BoxingInterpreter extends OptimizationBasicInterpreter { + private static final ImmutableSet wrappersClassNames; + + static { + ImmutableSet.Builder wrappersClassesBuilder = ImmutableSet.builder(); + + for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) { + wrappersClassesBuilder.add(AsmUtil.internalNameByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName())); + } + + wrappersClassNames = wrappersClassesBuilder.build(); + } + private final Map boxingPlaces = new HashMap(); private final InsnList insnList; @@ -38,24 +54,15 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { this.insnList = insnList; } - private static boolean isClassBox(@NotNull String owner) { - - if (!owner.startsWith("java/lang/")) { - return false; - } - - String className = owner.substring("java/lang/".length()); - - return (className.equals("Integer") || - className.equals("Double") || - className.equals("Long") || - className.equals("Char") || - className.equals("Byte") || - className.equals("Boolean")) || - className.endsWith("Number"); + private static boolean isWrapperClassName(@NotNull String owner) { + return wrappersClassNames.contains(owner); } - private static boolean isUnboxingMethod(@NotNull String name) { + private static boolean isWrapperClassNameOrNumber(@NotNull String owner) { + return isWrapperClassName(owner) || owner.equals(Type.getInternalName(Number.class)); + } + + private static boolean isUnboxingMethodName(@NotNull String name) { return name.endsWith("Value"); } @@ -66,7 +73,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { MethodInsnNode methodInsn = (MethodInsnNode) insn; - return isClassBox(methodInsn.owner) && isUnboxingMethod(methodInsn.name); + return isWrapperClassNameOrNumber(methodInsn.owner) && isUnboxingMethodName(methodInsn.name); } private static boolean isBoxing(@NotNull AbstractInsnNode insn) { @@ -76,7 +83,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - return isClassBox(methodInsnNode.owner) && methodInsnNode.name.equals("valueOf"); + return isWrapperClassName(methodInsnNode.owner) && methodInsnNode.name.equals("valueOf"); } @Override @@ -87,32 +94,30 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { if (isBoxing(insn)) { int index = insnList.indexOf(insn); if (!boxingPlaces.containsKey(index)) { - BoxedBasicValue boxedBasicValue = new BoxedBasicValue(value.getType(), values.get(0).getType(), insn); + BoxedBasicValue boxedBasicValue = new BoxedBasicValue(values.get(0).getType(), insn); onNewBoxedValue(boxedBasicValue); boxingPlaces.put(index, boxedBasicValue); } return boxingPlaces.get(index); - } - - if (isUnboxing(insn) && + } else if (isUnboxing(insn) && values.get(0) instanceof BoxedBasicValue && - value.getType().equals(((BoxedBasicValue) values.get(0)).getBoxedType())) { + value.getType().equals(((BoxedBasicValue) values.get(0)).getPrimitiveType())) { + BoxedBasicValue boxedBasicValue = (BoxedBasicValue) values.get(0); boxedBasicValue.addInsn(insn); boxedBasicValue.setWasUnboxed(true); + } else { + for (BasicValue arg : values) { + if (arg instanceof BoxedBasicValue) { + onMethodCallWithBoxedValue((BoxedBasicValue) arg); + } + } } return value; } - protected void onNewBoxedValue(BoxedBasicValue value) { - - } - - protected boolean isAllowedUnaryOperationWithBoxed(int opcode) { - return opcode == Opcodes.CHECKCAST || opcode == Opcodes.IFNULL; - } @Override @Nullable @@ -128,10 +133,37 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter { @Override @NotNull public BasicValue merge(@NotNull BasicValue v, @NotNull BasicValue w) { - if (v instanceof BoxedBasicValue && w instanceof BoxedBasicValue && v.equals(w)) { + if (v instanceof BoxedBasicValue && v.equals(w)) { return v; } + if (v instanceof BoxedBasicValue) { + onMergeFail((BoxedBasicValue) v); + v = new BasicValue(v.getType()); + } + + if (w instanceof BoxedBasicValue) { + onMergeFail((BoxedBasicValue) w); + w = new BasicValue(w.getType()); + } + return super.merge(v, w); } + + + protected void onNewBoxedValue(BoxedBasicValue value) { + + } + + protected void onMethodCallWithBoxedValue(BoxedBasicValue value) { + + } + + protected void onMergeFail(BoxedBasicValue value) { + + } + + protected boolean isAllowedUnaryOperationWithBoxed(int opcode) { + return opcode == Opcodes.CHECKCAST || opcode == Opcodes.IFNULL; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java index b6ab61905ff..726bf0e67b9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/boxing/RedundantBoxingInterpreter.java @@ -36,8 +36,17 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { } @Override - protected void onNewBoxedValue(BoxedBasicValue value) { - candidatesBoxedValues.add(value); + public BasicValue binaryOperation( + @NotNull AbstractInsnNode insn, + @NotNull BasicValue value1, + @NotNull BasicValue value2 + ) throws AnalyzerException { + + if (insn.getOpcode() == Opcodes.PUTFIELD && value2 instanceof BoxedBasicValue) { + markAsDirty((BoxedBasicValue) value2); + } + + return super.binaryOperation(insn, value1, value2); } @Override @@ -50,7 +59,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { public BasicValue copyOperation(@NotNull AbstractInsnNode insn, @NotNull BasicValue value) throws AnalyzerException { // currently we don't allow any copy operations with boxed values if (value instanceof BoxedBasicValue) { - candidatesBoxedValues.remove(value); + markAsDirty((BoxedBasicValue) value); return new BasicValue(value.getType()); } @@ -58,23 +67,22 @@ class RedundantBoxingInterpreter extends BoxingInterpreter { } @Override - @NotNull - public BasicValue merge(@NotNull BasicValue v, @NotNull BasicValue w) { - if (v instanceof BoxedBasicValue && w instanceof BoxedBasicValue && v == w) { - return v; - } + protected void onNewBoxedValue(BoxedBasicValue value) { + candidatesBoxedValues.add(value); + } - if (v instanceof BoxedBasicValue) { - candidatesBoxedValues.remove(v); - v = new BasicValue(v.getType()); - } + private void markAsDirty(BoxedBasicValue value) { + candidatesBoxedValues.remove(value); + } - if (w instanceof BoxedBasicValue) { - candidatesBoxedValues.remove(w); - w = new BasicValue(w.getType()); - } + @Override + protected void onMethodCallWithBoxedValue(BoxedBasicValue value) { + markAsDirty(value); + } - return super.merge(v, w); + @Override + protected void onMergeFail(BoxedBasicValue v) { + markAsDirty(v); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/transformer/MethodTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/transformer/MethodTransformer.java index d34a72f7d98..6293f7b4a09 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/optimization/transformer/MethodTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/optimization/transformer/MethodTransformer.java @@ -24,10 +24,10 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame; import org.jetbrains.org.objectweb.asm.tree.analysis.Value; public abstract class MethodTransformer { - private final MethodTransformer methodTransformer; + private final MethodTransformer delegate; - protected MethodTransformer(MethodTransformer methodTransformer) { - this.methodTransformer = methodTransformer; + protected MethodTransformer(MethodTransformer delegate) { + this.delegate = delegate; } protected static Frame[] runAnalyzer( @@ -44,8 +44,8 @@ public abstract class MethodTransformer { } public void transform(@NotNull String owner, @NotNull MethodNode methodNode) { - if (methodTransformer != null) { - methodTransformer.transform(owner, methodNode); + if (delegate != null) { + delegate.transform(owner, methodNode); } } }