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 Type fieldType = JetTypeMapper.psiTypeToAsm(psiField.getType());
final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC); final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
if (!isStatic) { if (!isStatic) {
ensureReceiverOnStack(expression, null); ensureReceiverOnStack(expression, null, JetTypeMapper.TYPE_OBJECT);
} }
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic)); 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 boolean forceInterface = receiver != null && !(receiver instanceof JetThisExpression);
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface); final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface);
if (!isStatic) { if (!isStatic) {
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null); ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null, JetTypeMapper.TYPE_OBJECT);
} }
myStack.push(iValue); myStack.push(iValue);
} }
@@ -877,7 +877,7 @@ public class ExpressionCodegen extends JetVisitor {
setOwnerFromCall(callableMethod, expression); setOwnerFromCall(callableMethod, expression);
} }
if (callableMethod.needsReceiverOnStack() && !haveReceiver) { if (callableMethod.needsReceiverOnStack() && !haveReceiver) {
ensureReceiverOnStack(expression, callableMethod.getReceiverClass()); ensureReceiverOnStack(expression, callableMethod.getReceiverClass(), JetTypeMapper.TYPE_OBJECT);
} }
pushMethodArguments(expression, callableMethod.getValueParameterTypes()); pushMethodArguments(expression, callableMethod.getValueParameterTypes());
if (callableMethod.acceptsTypeArguments()) { if (callableMethod.acceptsTypeArguments()) {
@@ -906,7 +906,16 @@ public class ExpressionCodegen extends JetVisitor {
return null; 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); JetExpression receiver = getReceiverForSelector(expression);
if (receiver != null) { if (receiver != null) {
if (!resolvesToClassOrPackage(receiver)) { if (!resolvesToClassOrPackage(receiver)) {
@@ -914,13 +923,14 @@ public class ExpressionCodegen extends JetVisitor {
if (myStack.isEmpty()) { if (myStack.isEmpty()) {
throw new IllegalStateException("expected receiver on stack but it's not there: " + receiver.getText()); 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) && else if (!(expression.getParent() instanceof JetSafeQualifiedExpression) &&
!(expression.getParent() instanceof JetPredicateExpression)) { !(expression.getParent() instanceof JetPredicateExpression)) {
generateThisOrOuter(calleeContainingClass); return generateThisOrOuter(calleeContainingClass);
} }
return null;
} }
private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) { 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; boolean thisDone = false;
StackValue result = null;
ClassContext cur = context; ClassContext cur = context;
while (true) { while (true) {
@@ -973,16 +984,16 @@ public class ExpressionCodegen extends JetVisitor {
} }
thisDone = true; thisDone = true;
outer.put(outer.type, v); result = outer;
} }
cur = parentContext; cur = parentContext;
} }
if (!thisDone) { if (!thisDone) {
thisToStack(); return thisExpression();
} }
return result;
} }
private static boolean isReceiver(PsiElement expression) { private static boolean isReceiver(PsiElement expression) {
@@ -1513,8 +1524,7 @@ public class ExpressionCodegen extends JetVisitor {
public void visitThisExpression(JetThisExpression expression) { public void visitThisExpression(JetThisExpression expression) {
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference()); final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference());
if (descriptor instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor) {
generateThisOrOuter((ClassDescriptor) descriptor); myStack.push(generateThisOrOuter((ClassDescriptor) descriptor));
myStack.push(StackValue.onStack(JetTypeMapper.TYPE_OBJECT));
} }
else { else {
generateThis(); generateThis();
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@@ -15,7 +16,7 @@ import java.util.List;
public class ArraySize implements IntrinsicMethod { public class ArraySize implements IntrinsicMethod {
@Override @Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) { 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(); v.arraylength();
return StackValue.onStack(Type.INT_TYPE); return StackValue.onStack(Type.INT_TYPE);
} }
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@@ -21,10 +22,17 @@ public class BinaryOp implements IntrinsicMethod {
@Override @Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) { 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(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)); v.visitInsn(expectedType.getOpcode(opcode));
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
@@ -15,7 +15,13 @@ import java.util.List;
public class Not implements IntrinsicMethod { public class Not implements IntrinsicMethod {
@Override @Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) { 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); return StackValue.not(stackValue);
} }
} }
@@ -15,7 +15,12 @@ import java.util.List;
public class UnaryMinus implements IntrinsicMethod { public class UnaryMinus implements IntrinsicMethod {
@Override @Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) { 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); v.neg(expectedType);
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
@@ -463,4 +463,22 @@ public class NamespaceGenTest extends CodegenTestCase {
final Method main = generateFunction(); final Method main = generateFunction();
assertEquals("IntelliJ IDEA Rulezzz", main.invoke(null, "IDEA")); 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());
}
} }