support explicit calls to some intrinsic functions

This commit is contained in:
Dmitry Jemerov
2011-07-15 19:26:05 +02:00
parent 3592aff812
commit cfca58bc06
6 changed files with 65 additions and 17 deletions
@@ -666,7 +666,7 @@ public class ExpressionCodegen extends JetVisitor {
final Type fieldType = JetTypeMapper.psiTypeToAsm(psiField.getType());
final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
if (!isStatic) {
ensureReceiverOnStack(expression, null);
ensureReceiverOnStack(expression, null, JetTypeMapper.TYPE_OBJECT);
}
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
}
@@ -710,7 +710,7 @@ public class ExpressionCodegen extends JetVisitor {
final boolean forceInterface = receiver != null && !(receiver instanceof JetThisExpression);
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface);
if (!isStatic) {
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null);
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null, JetTypeMapper.TYPE_OBJECT);
}
myStack.push(iValue);
}
@@ -877,7 +877,7 @@ public class ExpressionCodegen extends JetVisitor {
setOwnerFromCall(callableMethod, expression);
}
if (callableMethod.needsReceiverOnStack() && !haveReceiver) {
ensureReceiverOnStack(expression, callableMethod.getReceiverClass());
ensureReceiverOnStack(expression, callableMethod.getReceiverClass(), JetTypeMapper.TYPE_OBJECT);
}
pushMethodArguments(expression, callableMethod.getValueParameterTypes());
if (callableMethod.acceptsTypeArguments()) {
@@ -906,7 +906,16 @@ public class ExpressionCodegen extends JetVisitor {
return null;
}
public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) {
public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass,
final Type expectedReceiverType) {
final StackValue receiver = getReceiverAsStackValue(expression, calleeContainingClass, expectedReceiverType);
if (receiver != null) {
receiver.put(receiver.type, v);
}
}
@Nullable
public StackValue getReceiverAsStackValue(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass, Type expectedReceiverType) {
JetExpression receiver = getReceiverForSelector(expression);
if (receiver != null) {
if (!resolvesToClassOrPackage(receiver)) {
@@ -914,13 +923,14 @@ public class ExpressionCodegen extends JetVisitor {
if (myStack.isEmpty()) {
throw new IllegalStateException("expected receiver on stack but it's not there: " + receiver.getText());
}
myStack.pop().put(JetTypeMapper.TYPE_OBJECT, v);
return myStack.pop();
}
}
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression) &&
!(expression.getParent() instanceof JetPredicateExpression)) {
generateThisOrOuter(calleeContainingClass);
return generateThisOrOuter(calleeContainingClass);
}
return null;
}
private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) {
@@ -948,8 +958,9 @@ public class ExpressionCodegen extends JetVisitor {
}
}
public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) {
boolean thisDone = false;
StackValue result = null;
ClassContext cur = context;
while (true) {
@@ -973,16 +984,16 @@ public class ExpressionCodegen extends JetVisitor {
}
thisDone = true;
outer.put(outer.type, v);
result = outer;
}
cur = parentContext;
}
if (!thisDone) {
thisToStack();
return thisExpression();
}
return result;
}
private static boolean isReceiver(PsiElement expression) {
@@ -1513,8 +1524,7 @@ public class ExpressionCodegen extends JetVisitor {
public void visitThisExpression(JetThisExpression expression) {
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference());
if (descriptor instanceof ClassDescriptor) {
generateThisOrOuter((ClassDescriptor) descriptor);
myStack.push(StackValue.onStack(JetTypeMapper.TYPE_OBJECT));
myStack.push(generateThisOrOuter((ClassDescriptor) descriptor));
}
else {
generateThis();
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type;
@@ -15,7 +16,7 @@ import java.util.List;
public class ArraySize implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
codegen.ensureReceiverOnStack(element, null);
codegen.ensureReceiverOnStack(element, null, JetTypeMapper.TYPE_OBJECT);
v.arraylength();
return StackValue.onStack(Type.INT_TYPE);
}
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type;
@@ -21,10 +22,17 @@ public class BinaryOp implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
if (!haveReceiver) {
if (arguments.size() == 1) {
// intrinsic is called as an ordinary function
codegen.ensureReceiverOnStack(element, null, expectedType);
codegen.gen(arguments.get(0), expectedType);
}
codegen.gen(arguments.get(1), expectedType);
else {
if (!haveReceiver) {
codegen.gen(arguments.get(0), expectedType);
}
codegen.gen(arguments.get(1), expectedType);
}
v.visitInsn(expectedType.getOpcode(opcode));
return StackValue.onStack(expectedType);
}
@@ -15,7 +15,13 @@ import java.util.List;
public class Not implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
final StackValue stackValue = codegen.generateIntermediateValue(arguments.get(0));
final StackValue stackValue;
if (arguments.size() == 1) {
stackValue = codegen.generateIntermediateValue(arguments.get(0));
}
else {
stackValue = codegen.getReceiverAsStackValue(element, null, expectedType);
}
return StackValue.not(stackValue);
}
}
@@ -15,7 +15,12 @@ import java.util.List;
public class UnaryMinus implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
codegen.gen(arguments.get(0), expectedType);
if (arguments.size() == 1) {
codegen.gen(arguments.get(0), expectedType);
}
else {
codegen.ensureReceiverOnStack(element, null, expectedType);
}
v.neg(expectedType);
return StackValue.onStack(expectedType);
}
@@ -463,4 +463,22 @@ public class NamespaceGenTest extends CodegenTestCase {
final Method main = generateFunction();
assertEquals("IntelliJ IDEA Rulezzz", main.invoke(null, "IDEA"));
}
public void testExplicitCallOfBinaryOpIntrinsic() throws Exception {
loadText("fun foo(a: Int) = a.plus(1)");
final Method main = generateFunction();
assertEquals(2, ((Integer) main.invoke(null, 1)).intValue());
}
public void testExplicitCallOfUnaryMinusIntrinsic() throws Exception {
loadText("fun foo(a: Int) = a.minus()");
final Method main = generateFunction();
assertEquals(-1, ((Integer) main.invoke(null, 1)).intValue());
}
public void testExplicitCallOfBooleanNotIntrinsic() throws Exception {
loadText("fun foo(a: Boolean) = a.not()");
final Method main = generateFunction();
assertEquals(false, ((Boolean) main.invoke(null, true)).booleanValue());
}
}