Number/Object compare to branched one

This commit is contained in:
Michael Bogdanov
2015-03-31 11:25:49 +03:00
parent 2946c1d6a8
commit ce004a9181
4 changed files with 217 additions and 162 deletions
@@ -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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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);
@@ -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 {
@@ -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)
}
@@ -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<Int, Int>()
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")
}
}
}
}