Number/Object compare to branched one
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user