postfix part of KT-471

This commit is contained in:
Alex Tkachman
2012-01-27 23:11:14 +03:00
parent 8d39594b91
commit 686d4cae3c
4 changed files with 211 additions and 17 deletions
@@ -2006,19 +2006,36 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Arrays.asList(expression.getBaseExpression()), receiver); Arrays.asList(expression.getBaseExpression()), receiver);
} }
else { else {
return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable); DeclarationDescriptor cls = op.getContainingDeclaration();
if (isNumberPrimitive(cls) || !(op.getName().equals("inc") || op.getName().equals("dec")) ) {
return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable);
}
else {
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
assert resolvedCall != null;
StackValue value = gen(expression.getBaseExpression());
value.dupReceiver(v);
value.dupReceiver(v);
Type type = expressionType(expression.getBaseExpression());
value.put(type, v);
((CallableMethod)callable).invoke(v);
value.store(v);
value.put(type, v);
return StackValue.onStack(type);
}
} }
} }
private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) { private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) {
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
assert resolvedCall != null; assert resolvedCall != null;
CallableMethod callableMethod = (CallableMethod) callable; genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callable);
genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callableMethod);
pushTypeArguments(resolvedCall); pushTypeArguments(resolvedCall);
pushMethodArguments(resolvedCall, callableMethod.getValueParameterTypes()); pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
callableMethod.invoke(v); callable.invoke(v);
return returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getAsmMethod().getReturnType()); return returnValueAsStackValue(op, callable.getSignature().getAsmMethod().getReturnType());
} }
@Override @Override
@@ -2027,19 +2044,63 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (op instanceof FunctionDescriptor) { if (op instanceof FunctionDescriptor) {
final Type asmType = expressionType(expression); final Type asmType = expressionType(expression);
DeclarationDescriptor cls = op.getContainingDeclaration(); DeclarationDescriptor cls = op.getContainingDeclaration();
if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) { if (op.getName().equals("inc") || op.getName().equals("dec")) {
receiver.put(receiver.type, v); if (isNumberPrimitive(cls)) {
JetExpression operand = expression.getBaseExpression(); receiver.put(receiver.type, v);
if (operand instanceof JetReferenceExpression) { JetExpression operand = expression.getBaseExpression();
final int index = indexOfLocal((JetReferenceExpression) operand); if (operand instanceof JetReferenceExpression) {
if (index >= 0 && isIntPrimitive(asmType)) { final int index = indexOfLocal((JetReferenceExpression) operand);
int increment = op.getName().equals("inc") ? 1 : -1; if (index >= 0 && isIntPrimitive(asmType)) {
return StackValue.postIncrement(index, increment); int increment = op.getName().equals("inc") ? 1 : -1;
return StackValue.postIncrement(index, increment);
}
} }
gen(operand, asmType); // old value
generateIncrement(op, asmType, operand, receiver); // increment in-place
return StackValue.onStack(asmType); // old value
}
else {
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
assert resolvedCall != null;
final Callable callable = resolveToCallable(op, false);
StackValue value = gen(expression.getBaseExpression());
value.dupReceiver(v);
Type type = expressionType(expression.getBaseExpression());
value.put(type, v);
switch(value.receiverSize()) {
case 0:
if(type.getSize() == 2)
v.dup2();
else
v.dup();
break;
case 1:
if(type.getSize() == 2)
v.dup2X1();
else
v.dupX1();
break;
case 2:
if(type.getSize() == 2)
v.dup2X2();
else
v.dupX2();
break;
case -1:
throw new UnsupportedOperationException();
}
((CallableMethod)callable).invoke(v);
value.store(v);
return StackValue.onStack(type);
} }
gen(operand, asmType); // old value
generateIncrement(op, asmType, operand, receiver); // increment in-place
return StackValue.onStack(asmType); // old value
} }
} }
throw new UnsupportedOperationException("Don't know how to generate this prefix expression"); throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
@@ -51,6 +51,10 @@ public abstract class StackValue {
public void dupReceiver(InstructionAdapter v) { public void dupReceiver(InstructionAdapter v) {
} }
public int receiverSize() {
return 0;
}
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
if (this.type == Type.BOOLEAN_TYPE) { if (this.type == Type.BOOLEAN_TYPE) {
put(Type.BOOLEAN_TYPE, v); put(Type.BOOLEAN_TYPE, v);
@@ -491,6 +495,10 @@ public abstract class StackValue {
public void dupReceiver(InstructionAdapter v) { public void dupReceiver(InstructionAdapter v) {
v.dup2(); // array and index v.dup2(); // array and index
} }
public int receiverSize() {
return 2;
}
} }
private static class CollectionElement extends StackValue { private static class CollectionElement extends StackValue {
@@ -547,6 +555,15 @@ public abstract class StackValue {
((IntrinsicMethod)setter).generate(codegen, v, null, null, null, null); ((IntrinsicMethod)setter).generate(codegen, v, null, null, null, null);
} }
public int receiverSize() {
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
return 2;
}
else {
return -1;
}
}
@Override @Override
public void dupReceiver(InstructionAdapter v) { public void dupReceiver(InstructionAdapter v) {
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) { if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
@@ -686,6 +703,9 @@ public abstract class StackValue {
} }
private boolean isStandardStack(ResolvedCall call) { private boolean isStandardStack(ResolvedCall call) {
if(call == null)
return true;
for (TypeParameterDescriptor typeParameterDescriptor : call.getResultingDescriptor().getTypeParameters()) { for (TypeParameterDescriptor typeParameterDescriptor : call.getResultingDescriptor().getTypeParameters()) {
if(typeParameterDescriptor.isReified()) if(typeParameterDescriptor.isReified())
return false; return false;
@@ -736,6 +756,10 @@ public abstract class StackValue {
} }
} }
public int receiverSize() {
return isStatic ? 0 : 1;
}
@Override @Override
public void store(InstructionAdapter v) { public void store(InstructionAdapter v) {
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor()); v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
@@ -801,6 +825,10 @@ public abstract class StackValue {
v.dup(); v.dup();
} }
} }
public int receiverSize() {
return isStatic ? 0 : 1;
}
} }
private static class Expression extends StackValue { private static class Expression extends StackValue {
@@ -904,6 +932,10 @@ public abstract class StackValue {
v.dup(); v.dup();
} }
public int receiverSize() {
return 1;
}
@Override @Override
public void put(Type type, InstructionAdapter v) { public void put(Type type, InstructionAdapter v) {
Type sharedType = sharedTypeForType(this.type); Type sharedType = sharedTypeForType(this.type);
@@ -0,0 +1,97 @@
import java.util.ArrayList
class MyNumber(val i: Int) {
fun inc(): MyNumber = MyNumber(i+1)
}
class MNR(var ref: MyNumber) {}
fun test1() : Boolean {
var m = MyNumber(42)
m++
if (m.i != 43) return false
return true
}
fun test2() : Boolean {
var m = MyNumber(44)
var m2 = m++
if (m2.i != 44) return false
if (m.i != 45) return false
return true
}
fun test3() : Boolean {
var mnr = MNR(MyNumber(42))
mnr.ref++
if (mnr.ref.i != 43) return false
return true
}
fun test4() : Boolean {
var mnr = MNR(MyNumber(42))
val m3 = mnr.ref++
if (m3.i != 42) return false
return true
}
fun test5() : Boolean {
var mnr = Array<MyNumber>(2,{MyNumber(42)})
mnr[0]++
if (mnr[0].i != 43) return false
return true
}
fun test6() : Boolean {
var mnr = Array<MyNumber>(2,{it -> MyNumber(42-it)})
mnr[1] = mnr[0]++
if (mnr[0].i != 43) return false
if (mnr[1].i != 42) return false
return true
}
/*
fun test7() : Boolean {
var mnr = ArrayList<MyNumber>()
mnr.add(MyNumber(42))
mnr[0]++
if (mnr[0].i != 43) return false
return true
}
fun test8() : Boolean {
var mnr = ArrayList<MyNumber>()
mnr.add(MyNumber(42))
mnr.add(MyNumber(41))
mnr[1] = mnr[0]++
if (mnr[0].i != 43) return false
if (mnr[1].i != 42) return false
return true
}
*/
fun box() : String {
var m = MyNumber(42)
if (!test1()) return "fail test 1"
if (!test2()) return "fail test 2"
if (!test3()) return "fail test 3"
if (!test4()) return "fail test 4"
if (!test5()) return "fail test 5"
if (!test6()) return "fail test 6"
/*
if (!test7()) return "fail test 7"
if (!test8()) return "fail test 8"
++m
if (m.i != 44) return "fail 0"
var m1 = ++m
if (m1.i != 46) return "fail 3"
if (m.i != 46) return "fail 4"
*/
return "OK"
}
@@ -261,4 +261,8 @@ public class ClassGenTest extends CodegenTestCase {
public void testkt1157() throws Exception { public void testkt1157() throws Exception {
blackBoxFile("regressions/kt1157.kt"); blackBoxFile("regressions/kt1157.kt");
} }
public void testkt471() throws Exception {
blackBoxFile("regressions/kt471.kt");
}
} }