diff --git a/idea/src/org/jetbrains/jet/codegen/CallableMethod.java b/idea/src/org/jetbrains/jet/codegen/CallableMethod.java index 6dc1280629b..1ff1be8a719 100644 --- a/idea/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/idea/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; @@ -15,6 +17,8 @@ public class CallableMethod { private final int invokeOpcode; private final List valueParameterTypes; private boolean acceptsTypeArguments = false; + private boolean needsReceiverOnStack = false; + private ClassDescriptor receiverClass = null; public CallableMethod(String owner, Method signature, int invokeOpcode, List valueParameterTypes) { this.owner = owner; @@ -51,6 +55,19 @@ public class CallableMethod { this.acceptsTypeArguments = acceptsTypeArguments; } + public void setNeedsReceiver(@Nullable ClassDescriptor receiverClass) { + needsReceiverOnStack = true; + this.receiverClass = receiverClass; + } + + public boolean needsReceiverOnStack() { + return needsReceiverOnStack; + } + + public ClassDescriptor getReceiverClass() { + return receiverClass; + } + void invoke(InstructionAdapter v) { v.visitMethodInsn(getInvokeOpcode(), getOwner(), getSignature().getName(), getSignature().getDescriptor()); } diff --git a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java index f21a5e12442..84c20b00f4c 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -245,6 +245,10 @@ public class ClosureCodegen { public static CallableMethod asCallableMethod(FunctionDescriptor fd) { Method descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); - return new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); + final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); + if (fd.getReceiverType() != null) { + result.setNeedsReceiver(null); + } + return result; } } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index e981c3a4440..663617e782e 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -768,31 +768,15 @@ public class ExpressionCodegen extends JetVisitor { final PsiMethod psiMethod = (PsiMethod) declarationPsiElement; callableMethod = JetTypeMapper.mapToCallableMethod(psiMethod); if (!psiMethod.hasModifierProperty(PsiModifier.STATIC)) { - ensureReceiverOnStack(expression, null); setOwnerFromCall(callableMethod, expression); } } else if (declarationPsiElement instanceof JetNamedFunction) { final JetNamedFunction jetFunction = (JetNamedFunction) declarationPsiElement; callableMethod = typeMapper.mapToCallableMethod(jetFunction); - - if (functionParent instanceof NamespaceDescriptorImpl) { - if (jetFunction.getReceiverTypeRef() != null) { - ensureReceiverOnStack(expression, null); - } - } - else if (functionParent instanceof ClassDescriptor) { - ensureReceiverOnStack(expression, (ClassDescriptor) functionParent); - } } else { gen(callee, Type.getObjectType(ClosureCodegen.getInternalClassName(fd))); - - boolean isExtensionFunction = fd.getReceiverType() != null; - if (isExtensionFunction) { - ensureReceiverOnStack(expression, null); - } - callableMethod = ClosureCodegen.asCallableMethod(fd); } @@ -843,6 +827,9 @@ public class ExpressionCodegen extends JetVisitor { } private void invokeMethodWithArguments(CallableMethod callableMethod, JetCallExpression expression) { + if (callableMethod.needsReceiverOnStack()) { + ensureReceiverOnStack(expression, callableMethod.getReceiverClass()); + } pushMethodArguments(expression, callableMethod.getValueParameterTypes()); if (callableMethod.acceptsTypeArguments()) { pushTypeArguments(expression); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 21c07068b4b..440e1c363e2 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -109,19 +109,27 @@ public class JetTypeMapper { List valueParameterTypes = new ArrayList(); Collections.addAll(valueParameterTypes, signature.getArgumentTypes()); int opcode; + boolean needsReceiver = false; if (method.isConstructor()) { opcode = Opcodes.INVOKESPECIAL; } else if (method.hasModifierProperty(PsiModifier.STATIC)) { opcode = Opcodes.INVOKESTATIC; } - else if (containingClass.isInterface()) { - opcode = Opcodes.INVOKEINTERFACE; - } else { - opcode = Opcodes.INVOKEVIRTUAL; + needsReceiver = true; + if (containingClass.isInterface()) { + opcode = Opcodes.INVOKEINTERFACE; + } + else { + opcode = Opcodes.INVOKEVIRTUAL; + } } - return new CallableMethod(owner, signature, opcode, valueParameterTypes); + final CallableMethod result = new CallableMethod(owner, signature, opcode, valueParameterTypes); + if (needsReceiver) { + result.setNeedsReceiver(null); + } + return result; } public String jvmName(ClassDescriptor jetClass, OwnerKind kind) { @@ -382,9 +390,12 @@ public class JetTypeMapper { Method descriptor = mapSignature(f, valueParameterTypes); String owner; int invokeOpcode; + boolean needsReceiver; + ClassDescriptor receiverClass = null; if (functionParent instanceof NamespaceDescriptor) { owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent)); invokeOpcode = Opcodes.INVOKESTATIC; + needsReceiver = f.getReceiverTypeRef() != null; } else if (functionParent instanceof ClassDescriptor) { ClassDescriptor containingClass = (ClassDescriptor) functionParent; @@ -392,6 +403,8 @@ public class JetTypeMapper { invokeOpcode = isInterface(containingClass, OwnerKind.INTERFACE) ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL; + needsReceiver = true; + receiverClass = containingClass; } else { throw new UnsupportedOperationException("unknown function parent"); @@ -399,6 +412,9 @@ public class JetTypeMapper { final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes); result.setAcceptsTypeArguments(true); + if (needsReceiver) { + result.setNeedsReceiver(receiverClass); + } return result; }