diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 6107f9cf723..4d857a9b215 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.codegen.inline.*; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; +import org.jetbrains.kotlin.codegen.stackvalue.BranchedValue; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.codegen.when.SwitchCodegen; @@ -436,7 +437,7 @@ public class ExpressionCodegen extends JetVisitor implem @Override public Unit invoke(InstructionAdapter v) { Label elseLabel = new Label(); - condition.condJump(elseLabel, true, v); // == 0, i.e. false + BranchedValue.Companion.condJump(condition, elseLabel, true, v); Label end = new Label(); @@ -463,7 +464,7 @@ public class ExpressionCodegen extends JetVisitor implem blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression))); StackValue conditionValue = gen(expression.getCondition()); - conditionValue.condJump(end, true, v); + BranchedValue.Companion.condJump(conditionValue, end, true, v); generateLoopBody(expression.getBody()); @@ -510,7 +511,7 @@ public class ExpressionCodegen extends JetVisitor implem conditionValue = gen(condition); } - conditionValue.condJump(beginLoopLabel, false, v); + BranchedValue.Companion.condJump(conditionValue, beginLoopLabel, false, v); v.mark(breakLabel); blockStackElements.pop(); @@ -1250,7 +1251,7 @@ public class ExpressionCodegen extends JetVisitor implem @Override public Unit invoke(InstructionAdapter v) { Label elseLabel = new Label(); - condition.condJump(elseLabel, inverse, v); + BranchedValue.Companion.condJump(condition, elseLabel, inverse, v); if (isStatement) { gen(expression, Type.VOID_TYPE); @@ -4099,7 +4100,7 @@ The "returned" value of try expression with no finally is either the last expres JetWhenCondition[] conditions = whenEntry.getConditions(); for (int i = 0; i < conditions.length; i++) { StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]); - conditionValue.condJump(nextCondition, true, v); + BranchedValue.Companion.condJump(conditionValue, nextCondition, true, v); if (i < conditions.length - 1) { v.goTo(thisEntry); v.mark(nextCondition); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index a8380e585d0..85b6fd69335 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.PrimitiveType; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod; +import org.jetbrains.kotlin.codegen.stackvalue.BranchedValue; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; @@ -138,17 +139,6 @@ public abstract class StackValue { throw new UnsupportedOperationException("Cannot store to value " + this); } - public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) { - put(this.type, v); - coerceTo(Type.BOOLEAN_TYPE, v); - if (jumpIfFalse) { - v.ifeq(label); - } - else { - v.ifne(label); - } - } - @NotNull public static Local local(int index, @NotNull Type type) { return new Local(index, type); @@ -166,17 +156,23 @@ public abstract class StackValue { @NotNull public static StackValue constant(@Nullable Object value, @NotNull Type type) { - return new Constant(value, type); + if (type == Type.BOOLEAN_TYPE) { + assert value instanceof Boolean : "Value for boolean constant should have boolean type: " + value; + return BranchedValue.Companion.booleanConstant((Boolean) value); + } + else { + return new Constant(value, type); + } } @NotNull public static StackValue cmp(@NotNull IElementType opToken, @NotNull Type type, StackValue left, StackValue right) { - return type.getSort() == Type.OBJECT ? new ObjectCompare(opToken, type, left, right) : new NumberCompare(opToken, type, left, right); + return BranchedValue.Companion.cmp(opToken, type, left, right); } @NotNull public static StackValue not(@NotNull StackValue stackValue) { - return new Invert(stackValue); + return BranchedValue.Companion.createInvertValue(stackValue); } @NotNull @@ -379,17 +375,6 @@ public abstract class StackValue { return UNIT; } - public void putAsBoolean(InstructionAdapter v) { - Label ifTrue = new Label(); - Label end = new Label(); - condJump(ifTrue, false, v); - v.iconst(0); - v.goTo(end); - v.mark(ifTrue); - v.iconst(1); - v.mark(end); - } - public static StackValue none() { return None.INSTANCE; } @@ -631,129 +616,6 @@ public abstract class StackValue { coerceTo(type, v); } - - @Override - public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) { - if (value instanceof Boolean) { - boolean boolValue = (Boolean) value; - if (boolValue ^ jumpIfFalse) { - v.goTo(label); - } - } - else { - throw new UnsupportedOperationException("don't know how to generate this condjump"); - } - } - } - - private static class NumberCompare extends StackValue { - protected final IElementType opToken; - protected final Type operandType; - protected final StackValue left; - protected final StackValue right; - - public NumberCompare(IElementType opToken, Type operandType, StackValue left, StackValue right) { - super(Type.BOOLEAN_TYPE); - this.opToken = opToken; - this.operandType = operandType; - this.left = left; - this.right = right; - } - - @Override - public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { - putAsBoolean(v); - coerceTo(type, v); - } - - @Override - public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) { - left.put(this.operandType, v); - right.put(this.operandType, v); - int opcode; - if (opToken == JetTokens.EQEQ || opToken == JetTokens.EQEQEQ) { - opcode = jumpIfFalse ? IFNE : IFEQ; - } - else if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) { - opcode = jumpIfFalse ? IFEQ : IFNE; - } - else if (opToken == JetTokens.GT) { - opcode = jumpIfFalse ? IFLE : IFGT; - } - else if (opToken == JetTokens.GTEQ) { - opcode = jumpIfFalse ? IFLT : IFGE; - } - else if (opToken == JetTokens.LT) { - opcode = jumpIfFalse ? IFGE : IFLT; - } - else if (opToken == JetTokens.LTEQ) { - opcode = jumpIfFalse ? IFGT : IFLE; - } - else { - throw new UnsupportedOperationException("Don't know how to generate this condJump: " + opToken); - } - if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) { - if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { - v.cmpl(operandType); - } - else { - v.cmpg(operandType); - } - } - else if (operandType == Type.LONG_TYPE) { - v.lcmp(); - } - else { - opcode += (IF_ICMPEQ - IFEQ); - } - v.visitJumpInsn(opcode, label); - } - } - - private static class ObjectCompare extends NumberCompare { - public ObjectCompare(IElementType opToken, Type operandType, StackValue left, StackValue right) { - super(opToken, operandType, left, right); - } - - @Override - public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) { - left.put(this.operandType, v); - right.put(this.operandType, v); - int opcode; - if (opToken == JetTokens.EQEQEQ) { - opcode = jumpIfFalse ? IF_ACMPNE : IF_ACMPEQ; - } - else if (opToken == JetTokens.EXCLEQEQEQ) { - opcode = jumpIfFalse ? IF_ACMPEQ : IF_ACMPNE; - } - else { - throw new UnsupportedOperationException("don't know how to generate this condjump"); - } - v.visitJumpInsn(opcode, label); - } - } - - private static class Invert extends StackValue { - private final StackValue myOperand; - - private Invert(StackValue operand) { - super(Type.BOOLEAN_TYPE); - myOperand = operand; - if (myOperand.type != Type.BOOLEAN_TYPE) { - throw new UnsupportedOperationException("operand of ! must be boolean"); - } - } - - @Override - public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { - putAsBoolean(v); - coerceTo(type, v); - } - - @Override - public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) { - myOperand.condJump(label, !jumpIfFalse, v); - } } private static class ArrayElement extends StackValueWithSimpleReceiver { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt index 954497344b3..6d03eb287be 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.kt @@ -39,10 +39,6 @@ class CoercionValue( value.putReceiver(v, isRead) } - override fun condJump(label: Label, jumpIfFalse: Boolean, v: InstructionAdapter) { - value.condJump(label, jumpIfFalse, v) - } - override fun isNonStaticAccess(isRead: Boolean): Boolean { return value.isNonStaticAccess(isRead) } @@ -54,11 +50,6 @@ public class StackValueWithLeaveTask( val leaveTasks: StackValueWithLeaveTask.() -> Unit ) : StackValue(stackValue.type) { - override fun condJump(label: Label, jumpIfFalse: Boolean, v: InstructionAdapter) { - stackValue.condJump(label, jumpIfFalse, v) - leaveTasks() - } - override fun putReceiver(v: InstructionAdapter, isRead: Boolean) { stackValue.putReceiver(v, isRead) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/stackvalue/BranchedValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/stackvalue/BranchedValue.kt new file mode 100644 index 00000000000..cbfcc3ffe70 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/stackvalue/BranchedValue.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.stackvalue + +import com.intellij.psi.tree.IElementType +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.Opcodes.* +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val operandType: Type, val opcode: Int) : StackValue(Type.BOOLEAN_TYPE) { + + constructor(or: BranchedValue, opcode: Int) : this(or.arg1, or.arg2, or.operandType, opcode) { + } + + override fun putSelector(type: Type, v: InstructionAdapter) { + val branchJumpLabel = Label() + condJump(branchJumpLabel, v) + val endLabel = Label() + v.iconst(1) + v.visitJumpInsn(GOTO, endLabel) + v.visitLabel(branchJumpLabel) + v.iconst(0) + v.visitLabel(endLabel) + coerceTo(type, v); + } + + open fun condJump(jumpIfFalse: Label, v: InstructionAdapter) { + arg1.put(operandType, v) + arg2?.put(operandType, v) + v.visitJumpInsn(patchOpcode(opcode, v), jumpIfFalse); + } + + protected open fun invert(): BranchedValue { + return BranchedValue(this, negatedOperations.get(opcode)) + } + + protected open fun patchOpcode(opcode: Int, v: InstructionAdapter): Int { + return opcode + } + + companion object { + val negatedOperations = hashMapOf() + + val TRUE: BranchedValue = object : BranchedValue(StackValue.Constant(true, Type.BOOLEAN_TYPE), null, Type.BOOLEAN_TYPE, IFEQ) { + override fun invert(): BranchedValue { + return FALSE + } + + override fun condJump(jumpIfFalse: Label, v: InstructionAdapter) { + + } + + override fun putSelector(type: Type, v: InstructionAdapter) { + v.iconst(1) + coerceTo(type, v); + } + } + val FALSE: BranchedValue = object : BranchedValue(StackValue.Constant(false, Type.BOOLEAN_TYPE), null, Type.BOOLEAN_TYPE, IFEQ) { + override fun invert(): BranchedValue { + return TRUE + } + + override fun condJump(jumpIfFalse: Label, v: InstructionAdapter) { + v.goTo(jumpIfFalse) + } + + override fun putSelector(type: Type, v: InstructionAdapter) { + v.iconst(0) + coerceTo(type, v); + } + } + + init { + registerOperations(IFNE, IFEQ) + registerOperations(IFLE, IFGT) + registerOperations(IFLT, IFGE) + registerOperations(IFGE, IFLT) + registerOperations(IFGT, IFLE) + registerOperations(IF_ACMPNE, IF_ACMPEQ) + } + + private fun registerOperations(op: Int, negatedOp: Int) { + negatedOperations.put(op, negatedOp) + negatedOperations.put(negatedOp, op) + } + + fun booleanConstant(value: Boolean): BranchedValue { + return if (value) TRUE else FALSE + } + + fun createInvertValue(argument: StackValue): StackValue { + if (argument.type != Type.BOOLEAN_TYPE) { + throw UnsupportedOperationException("operand of ! must be boolean") + } + + if (argument is BranchedValue) { + return argument.invert() + } + return BranchedValue(argument, null, Type.BOOLEAN_TYPE, IFNE) + } + + fun condJump(condition: StackValue, label: Label, jumpIfFalse: Boolean, iv: InstructionAdapter) { + var condJump: BranchedValue = if (condition is BranchedValue) { + condition + } + else { + BranchedValue(condition, null, Type.BOOLEAN_TYPE, IFEQ) + } + condJump = if (jumpIfFalse) condJump else condJump.invert() + condJump.condJump(label, iv) + } + + public fun cmp(opToken: IElementType, operandType: Type, left: StackValue, right: StackValue): StackValue = + if (operandType.getSort() == Type.OBJECT) + ObjectCompare(opToken, ObjectCompare.getObjectCompareOpcode(opToken), operandType, left, right) + else + NumberCompare(opToken, NumberCompare.getNumberCompareOpcode(opToken), operandType, left, right) + + } +} + + +class NumberCompare(val opToken: IElementType, opcode: Int, operandType: Type, left: StackValue, right: StackValue) : + BranchedValue(left, right, operandType, opcode) { + + override fun invert(): BranchedValue { + return NumberCompare(opToken, BranchedValue.negatedOperations[opcode], operandType, arg1, arg2!!) + } + + override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int { + when (operandType) { + Type.FLOAT_TYPE, Type.DOUBLE_TYPE -> { + if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { + v.cmpl(operandType) + } + else { + v.cmpg(operandType) + } + } + Type.LONG_TYPE -> { + v.lcmp() + } + else -> { + return opcode + (IF_ICMPEQ - IFEQ) + } + } + return opcode + } + + companion object { + fun getNumberCompareOpcode(opToken: IElementType): Int { + return when (opToken) { + JetTokens.EQEQ, JetTokens.EQEQEQ -> IFNE + JetTokens.EXCLEQ, JetTokens.EXCLEQEQEQ -> IFEQ + JetTokens.GT -> IFLE + JetTokens.GTEQ -> IFLT + JetTokens.LT -> IFGE + JetTokens.LTEQ -> IFGT + else -> { + throw UnsupportedOperationException("Don't know how to generate this condJump: " + opToken) + } + } + } + } +} + +class ObjectCompare(val opToken: IElementType, opcode: Int, operandType: Type, left: StackValue, right: StackValue) : + BranchedValue(left, right, operandType, opcode) { + + override fun invert(): BranchedValue { + return ObjectCompare(opToken, BranchedValue.negatedOperations[opcode], operandType, arg1, arg2!!) + } + + companion object { + fun getObjectCompareOpcode(opToken: IElementType): Int { + return when (opToken) { + JetTokens.EQEQEQ -> IF_ACMPNE + JetTokens.EXCLEQEQEQ -> IF_ACMPEQ + else -> throw UnsupportedOperationException("don't know how to generate this condjump") + } + } + } +} \ No newline at end of file