support explicit calls to some intrinsic functions
This commit is contained in:
@@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user