diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index 01b0d082f3b..4582e2e5e6c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; @@ -89,4 +90,12 @@ public class CallableMethod implements Callable { public Type getGenerateCalleeType() { return generateCalleeType; } + + public void invokeWithDefault(InstructionAdapter v, int mask) { + v.iconst(mask); + String desc = getSignature().getDescriptor().replace(")", "I)"); + if(getInvokeOpcode() != Opcodes.INVOKESTATIC) + desc = desc.replace("(", "(L" + getOwner() + ";"); + v.visitMethodInsn(Opcodes.INVOKESTATIC, getInvokeOpcode() == Opcodes.INVOKEINTERFACE ? getOwner() + "$$TImpl" : getOwner(), getSignature().getName() + "$default", desc); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 8e507409cb9..81d12c3f568 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -13,10 +13,7 @@ import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; +import org.objectweb.asm.*; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.signature.SignatureWriter; @@ -26,6 +23,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import static org.objectweb.asm.Opcodes.*; + public class ClosureCodegen extends FunctionOrClosureCodegen { public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, ClassContext context) { @@ -68,8 +67,8 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { appendType(signatureWriter, funDescriptor.getReturnType(), '='); signatureWriter.visitEnd(); - cv.visit(Opcodes.V1_6, - Opcodes.ACC_PUBLIC, + cv.visit(V1_6, + ACC_PUBLIC, name, null, funClass, @@ -79,7 +78,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { generateBridge(name, funDescriptor, cv); - boolean captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); + captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); final Type enclosingType = context.enclosingClassType(state.getTypeMapper()); if (enclosingType == null) captureThis = false; @@ -89,6 +88,10 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { cv.visitField(0, "this$0", enclosingType.getDescriptor(), null, null); } + if(isConst()) { + generateConstInstance(); + } + cv.visitEnd(); final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis); @@ -99,6 +102,48 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { return answer; } + private void generateConstInstance() { + cv.visitField(ACC_PRIVATE| ACC_STATIC, "$instance", "Ljava/lang/ref/SoftReference;", null, null); + + MethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "$getInstance", "()L" + name + ";", null, new String[0]); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;"); + mv.visitInsn(DUP); + Label makeNew = new Label(); + mv.visitJumpInsn(IFNULL, makeNew); + + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ref/SoftReference", "get", "()Ljava/lang/Object;"); + mv.visitInsn(DUP); + + Label ret = new Label(); + mv.visitJumpInsn(IFNULL, makeNew); + mv.visitTypeInsn(CHECKCAST, name); + mv.visitJumpInsn(GOTO, ret); + + mv.visitLabel(makeNew); + mv.visitInsn(POP); + + mv.visitTypeInsn(NEW, "java/lang/ref/SoftReference"); + mv.visitInsn(DUP); + + mv.visitTypeInsn(NEW, name); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 0); + + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, name, "", "()V"); + + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ref/SoftReference", "", "(Ljava/lang/Object;)V"); + mv.visitFieldInsn(PUTSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;"); + + mv.visitVarInsn(ALOAD, 0); + + mv.visitLabel(ret); + mv.visitInsn(ARETURN); + mv.visitMaxs(0,0); + mv.visitEnd(); + } + private boolean generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) { final ClassContext closureContext = context.intoClosure(name, this); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); @@ -110,7 +155,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { final Method bridge = erasedInvokeSignature(funDescriptor); final Method delegate = invokeSignature(funDescriptor); - final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]); + final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]); mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); @@ -164,7 +209,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { } final Method constructor = new Method("", Type.VOID_TYPE, argTypes); - final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]); + final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]); mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen expressionCodegen = new ExpressionCodegen(mv, null, Type.VOID_TYPE, context, state); @@ -190,7 +235,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { StackValue.field(type, name, fieldName, false).store(iv); } - iv.visitInsn(Opcodes.RETURN); + iv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); @@ -219,7 +264,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { public static CallableMethod asCallableMethod(FunctionDescriptor fd) { Method descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); - final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); + final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); if (fd.getReceiverParameter().exists()) { result.setNeedsReceiver(null); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 782ec25c56a..17e9aa6a456 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.types.*; @@ -543,23 +544,29 @@ public class ExpressionCodegen extends JetVisitor { return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements()); } else { - final GeneratedAnonymousClassDescriptor closure = new ClosureCodegen(state, this, context).gen(expression); + ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context); + final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression); - v.anew(Type.getObjectType(closure.getClassname())); - v.dup(); - - final Method cons = closure.getConstructor(); - - if (closure.isCaptureThis()) { - v.load(0, JetTypeMapper.TYPE_OBJECT); + if(closureCodegen.isConst()) { + v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";"); } + else { + v.anew(Type.getObjectType(closure.getClassname())); + v.dup(); - for (int i = 0; i < closure.getArgs().size(); i++) { - StackValue arg = closure.getArgs().get(i); - arg.put(cons.getArgumentTypes()[i], v); + final Method cons = closure.getConstructor(); + + if (closure.isCaptureThis()) { + v.load(0, JetTypeMapper.TYPE_OBJECT); + } + + for (int i = 0; i < closure.getArgs().size(); i++) { + StackValue arg = closure.getArgs().get(i); + arg.put(cons.getArgumentTypes()[i], v); + } + + v.invokespecial(closure.getClassname(), "", cons.getDescriptor()); } - - v.invokespecial(closure.getClassname(), "", cons.getDescriptor()); return StackValue.onStack(Type.getObjectType(closure.getClassname())); } } @@ -1018,11 +1025,14 @@ public class ExpressionCodegen extends JetVisitor { } receiver.put(JetTypeMapper.TYPE_OBJECT, v); } - pushMethodArguments(expression, callableMethod.getValueParameterTypes()); + int mask = pushMethodArguments(expression, callableMethod.getValueParameterTypes()); if (callableMethod.acceptsTypeArguments()) { pushTypeArguments(expression); } - callableMethod.invoke(v); + if(mask == 0) + callableMethod.invoke(v); + else + callableMethod.invokeWithDefault(v, mask); } private void setOwnerFromCall(CallableMethod callableMethod, JetCallElement expression) { @@ -1118,11 +1128,52 @@ public class ExpressionCodegen extends JetVisitor { return false; } - private void pushMethodArguments(JetCallElement expression, List valueParameterTypes) { + private int pushMethodArguments(JetCallElement expression, List valueParameterTypes) { + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression()); List args = expression.getValueArguments(); - for (int i = 0, argsSize = args.size(); i < argsSize; i++) { - ValueArgument arg = args.get(i); - gen(arg.getArgumentExpression(), valueParameterTypes.get(i)); + if(resolvedCall != null) { + Map valueArguments = resolvedCall.getValueArguments(); + CallableDescriptor fd = resolvedCall.getResultingDescriptor(); + + int index = 0; + int mask = 0; + for (ValueParameterDescriptor valueParameterDescriptor : fd.getValueParameters()) { + ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameterDescriptor); + if(resolvedValueArgument instanceof ExpressionValueArgument) { + ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument; + gen(valueArgument.getExpression(), valueParameterTypes.get(index)); + } + else if(resolvedValueArgument instanceof DefaultValueArgument) { + Type type = valueParameterTypes.get(index); + if(type.getSort() == Type.OBJECT||type.getSort() == Type.ARRAY) + v.aconst(null); + else if(type.getSort() == Type.FLOAT) { + v.aconst(0f); + } + else if(type.getSort() == Type.DOUBLE) { + v.aconst(0d); + } + else { + v.iconst(0); + } + mask |= (1 << index); + } + else if(resolvedValueArgument instanceof VarargValueArgument) { + throw new UnsupportedOperationException("Varargs are not supported yet"); + } + else { + throw new UnsupportedOperationException(); + } + index++; + } + return mask; + } + else { + for (int i = 0, argsSize = args.size(); i < argsSize; i++) { + ValueArgument arg = args.get(i); + gen(arg.getArgumentExpression(), valueParameterTypes.get(i)); + } + return 0; } } @@ -1739,6 +1790,21 @@ public class ExpressionCodegen extends JetVisitor { } private void pushTypeArguments(JetCallElement expression) { +// todo when frontend calculates +// ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression()); +// if(resolvedCall != null) { +// Map typeArguments = resolvedCall.getTypeArguments(); +// CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); +// for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) { +// JetType jetType = typeArguments.get(typeParameterDescriptor); +// generateTypeInfo(jetType); +// } +// } +// else { +// for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) { +// pushTypeArgument(jetTypeArgument); +// } +// } for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) { pushTypeArgument(jetTypeArgument); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 1fcd98e320c..fcc3f8f0173 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -1,26 +1,22 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetNamedFunction; +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; +import org.objectweb.asm.*; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; import java.util.List; import java.util.Set; +import static org.objectweb.asm.Opcodes.*; + /** * @author max * @author yole + * @author alex.tkachman */ public class FunctionCodegen { private final ClassContext owner; @@ -54,74 +50,81 @@ public class FunctionCodegen { List paramDescrs = functionDescriptor.getValueParameters(); List typeParameters = functionDescriptor.getTypeParameters(); - int flags = Opcodes.ACC_PUBLIC; // TODO. + int flags = ACC_PUBLIC; // TODO. OwnerKind kind = context.getContextKind(); - if(kind == OwnerKind.TRAIT_IMPL && bodyExpressions == null) - return; + if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) { - boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL; - if (isStatic) flags |= Opcodes.ACC_STATIC; + boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL; + if (isStatic) flags |= ACC_STATIC; - boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration())); - if (isAbstract) flags |= Opcodes.ACC_ABSTRACT; + boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration())); + if (isAbstract) flags |= ACC_ABSTRACT; - final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); - if (!isAbstract) { - mv.visitCode(); - FrameMap frameMap = context.prepareFrame(); + final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); + if (!isAbstract) { + mv.visitCode(); + FrameMap frameMap = context.prepareFrame(); - ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state); + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state); - Type[] argTypes = jvmSignature.getArgumentTypes(); - for (int i = 0; i < paramDescrs.size(); i++) { - ValueParameterDescriptor parameter = paramDescrs.get(i); - frameMap.enter(parameter, argTypes[i].getSize()); - } - - for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { - int slot = frameMap.enterTemp(); - codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO)); - } - - if (kind instanceof OwnerKind.DelegateKind) { - OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; - InstructionAdapter iv = new InstructionAdapter(mv); - iv.load(0, JetTypeMapper.TYPE_OBJECT); - dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv); - for (int i = 0; i < argTypes.length; i++) { - Type argType = argTypes[i]; - iv.load(i + 1, argType); - } - iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor()); - iv.areturn(jvmSignature.getReturnType()); - } - else { + Type[] argTypes = jvmSignature.getArgumentTypes(); for (int i = 0; i < paramDescrs.size(); i++) { ValueParameterDescriptor parameter = paramDescrs.get(i); - - Type sharedVarType = codegen.getSharedVarType(parameter); - Type localVarType = state.getTypeMapper().mapType(parameter.getOutType()); - if(sharedVarType != null) { - int index = frameMap.getIndex(parameter); - mv.visitTypeInsn(Opcodes.NEW, sharedVarType.getInternalName()); - mv.visitInsn(Opcodes.DUP); - mv.visitInsn(Opcodes.DUP); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, sharedVarType.getInternalName(), "", "()V"); - mv.visitVarInsn(localVarType.getOpcode(Opcodes.ILOAD), index); - mv.visitFieldInsn(Opcodes.PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor()); - mv.visitVarInsn(sharedVarType.getOpcode(Opcodes.ISTORE), index); - } + frameMap.enter(parameter, argTypes[i].getSize()); } - codegen.returnExpression(bodyExpressions); - } - mv.visitMaxs(0, 0); - mv.visitEnd(); + for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + int slot = frameMap.enterTemp(); + codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO)); + } - generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind); + if (kind instanceof OwnerKind.DelegateKind) { + OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; + InstructionAdapter iv = new InstructionAdapter(mv); + iv.load(0, JetTypeMapper.TYPE_OBJECT); + dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv); + for (int i = 0; i < argTypes.length; i++) { + Type argType = argTypes[i]; + iv.load(i + 1, argType); + } + iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor()); + iv.areturn(jvmSignature.getReturnType()); + } + else { + for (int i = 0; i < paramDescrs.size(); i++) { + ValueParameterDescriptor parameter = paramDescrs.get(i); + + Type sharedVarType = codegen.getSharedVarType(parameter); + Type localVarType = state.getTypeMapper().mapType(parameter.getOutType()); + if (sharedVarType != null) { + int index = frameMap.getIndex(parameter); + mv.visitTypeInsn(NEW, sharedVarType.getInternalName()); + mv.visitInsn(DUP); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, sharedVarType.getInternalName(), "", "()V"); + mv.visitVarInsn(localVarType.getOpcode(ILOAD), index); + mv.visitFieldInsn(PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor()); + mv.visitVarInsn(sharedVarType.getOpcode(ISTORE), index); + } + } + + codegen.returnExpression(bodyExpressions); + } + try { + mv.visitMaxs(0, 0); + } + catch (Throwable t) { + System.out.println(t); + } + mv.visitEnd(); + + generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind); + } } + + generateDefaultIfNeeded(context, state, v, jvmSignature, functionDescriptor, kind); } static void generateBridgeIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { @@ -135,12 +138,153 @@ public class FunctionCodegen { } } + static void generateDefaultIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { + DeclarationDescriptor contextClass = owner.getContextClass(); + + if(kind != OwnerKind.TRAIT_IMPL) { + // we don't generate defaults for traits but do for traitImpl + if(contextClass instanceof ClassDescriptor) { + PsiElement psiElement = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, contextClass); + if(psiElement instanceof JetClass) { + JetClass element = (JetClass) psiElement; + if(element.isTrait()) + return; + } + } + } + + boolean needed = false; + for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { + if(parameterDescriptor.hasDefaultValue()) { + needed = true; + break; + } + } + + if(needed) { + boolean hasReceiver = functionDescriptor.getReceiverParameter().exists(); + boolean isStatic = kind == OwnerKind.NAMESPACE; + + if(kind == OwnerKind.TRAIT_IMPL) { + String correctedDescr = "(" + jvmSignature.getDescriptor().substring(jvmSignature.getDescriptor().indexOf(";") + 1); + jvmSignature = new Method(jvmSignature.getName(), correctedDescr); + } + + int flags = ACC_PUBLIC; // TODO. + + String ownerInternalName = contextClass instanceof NamespaceDescriptor ? + JetTypeMapper.jvmName((NamespaceDescriptor) contextClass) : + state.getTypeMapper().jvmName((ClassDescriptor) contextClass, OwnerKind.IMPLEMENTATION); + + String descriptor = jvmSignature.getDescriptor().replace(")","I)"); + if(!isStatic) + descriptor = descriptor.replace("(","(L" + ownerInternalName + ";"); + final MethodVisitor mv = v.visitMethod(flags| ACC_STATIC, jvmSignature.getName() + "$default", descriptor, null, null); + InstructionAdapter iv = new InstructionAdapter(mv); + mv.visitCode(); + + FrameMap frameMap = owner.prepareFrame(); + + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state); + + int var = 0; + if(!isStatic) { + frameMap.enterTemp(); + var++; + } + + if(hasReceiver) { + frameMap.enterTemp(); + var++; + } + + Type[] argTypes = jvmSignature.getArgumentTypes(); + List paramDescrs = functionDescriptor.getValueParameters(); + for (int i = 0; i < paramDescrs.size(); i++) { + ValueParameterDescriptor parameter = paramDescrs.get(i); + int size = argTypes[i + (hasReceiver ? 1 : 0)].getSize(); + var += size; + frameMap.enter(parameter, size); + } + + List typeParameters = functionDescriptor.getTypeParameters(); + for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + int slot = frameMap.enterTemp(); + codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO)); + var++; + } + + frameMap.enterTemp(); + + int maskIndex = var; + + var = 0; + if(!isStatic) { + mv.visitVarInsn(ALOAD, var++); + } + + if(hasReceiver) { + mv.visitVarInsn(ALOAD, var++); + } + + Type[] argumentTypes = jvmSignature.getArgumentTypes(); + for (int index = 0; index < paramDescrs.size(); index++) { + ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index); + + Type t = argumentTypes[(hasReceiver ? 1 : 0) + index]; + Label endArg = null; + if (parameterDescriptor.hasDefaultValue()) { + iv.load(maskIndex, Type.INT_TYPE); + iv.iconst(1 << index); + iv.and(Type.INT_TYPE); + Label loadArg = new Label(); + iv.ifeq(loadArg); + + JetParameter jetParameter = (JetParameter) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, parameterDescriptor); + codegen.gen(jetParameter.getDefaultValue(), t); + + endArg = new Label(); + iv.goTo(endArg); + + iv.mark(loadArg); + } + + iv.load(var, t); + var += t.getSize(); + + if (parameterDescriptor.hasDefaultValue()) { + iv.mark(endArg); + } + } + + for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + iv.load(var++, JetTypeMapper.TYPE_OBJECT); + } + + if(!isStatic) { + if(kind == OwnerKind.TRAIT_IMPL) { + iv.invokeinterface(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor()); + } + else + iv.invokevirtual(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor()); + } + else { + iv.invokestatic(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor()); + } + + iv.areturn(jvmSignature.getReturnType()); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + } + private static void checkOverride(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) { Type type1 = state.getTypeMapper().mapType(overriddenFunction.getOriginal().getReturnType()); Type type2 = state.getTypeMapper().mapType(functionDescriptor.getReturnType()); if(!type1.equals(type2)) { Method overriden = state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()); - int flags = Opcodes.ACC_PUBLIC; // TODO. + int flags = ACC_PUBLIC; // TODO. final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), overriden.getDescriptor(), null, null); mv.visitCode(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java index a6a57ece6b5..a9834ed153d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java @@ -13,6 +13,8 @@ import java.util.Map; * @author alex.tkachman */ public class FunctionOrClosureCodegen { + protected boolean captureThis; + public final GenerationState state; protected final ExpressionCodegen exprContext; protected final ClassContext context; @@ -54,4 +56,12 @@ public class FunctionOrClosureCodegen { return null; } + + public boolean isCaptureThis() { + return captureThis; + } + + public boolean isConst () { + return !captureThis && closure.isEmpty(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java index 73021e8890f..c5a870da312 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -55,6 +55,7 @@ public class ResolvedCall { private D resultingDescriptor; // Probably substituted private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method private ReceiverDescriptor receiverArgument = NO_RECEIVER; // receiver of an extension function + private final Map typeArguments = Maps.newLinkedHashMap(); private final Map autoCasts = Maps.newHashMap(); private final Map valueArguments = Maps.newHashMap(); @@ -144,4 +145,8 @@ public class ResolvedCall { public boolean isDirty() { return someArgumentHasNoType; } + + public Map getTypeArguments() { + return typeArguments; + } } diff --git a/idea/testData/codegen/functions/defaultargs.jet b/idea/testData/codegen/functions/defaultargs.jet new file mode 100644 index 00000000000..9486bf5b856 --- /dev/null +++ b/idea/testData/codegen/functions/defaultargs.jet @@ -0,0 +1,49 @@ +fun reformat( + str : String, + normalizeCase : Boolean = true, + uppercaseFirstLetter : Boolean = true, + divideByCamelHumps : Boolean = true, + wordSeparator : String = " " +) = + (normalizeCase, uppercaseFirstLetter, divideByCamelHumps, wordSeparator) + +trait A { + fun bar2(arg: Int = 239) : Int + + fun bar(arg: Int = 240) : Int = bar2(arg/2) +} + +open abstract class B() : A { + fun foo(arg: Int = 239 + 1) : Int = arg + + abstract fun foo2(arg: Int = 239) : Int + + override fun bar2(arg: Int) : Int = arg +} + +class C() : B() { + override fun foo2(arg: Int) : Int = arg +} + +// fun T.toPrefixedString(prefix: String = "") = prefix + (this as java.lang.Object).toString() + +fun box() : String { + val expected = (true, true, true, " ") + +// if("mama".toPrefixedString("papa") != "papamama") return "fail" +// if("mama".toPrefixedString() != "mama") return "fail" + if(C().bar(10) != 5) return "fail" + if(C().bar() != 120) return "fail" + if(C().foo(10) != 10) return "fail" + if(C().foo() != 240) return "fail" + if(C().foo2() != 239) return "fail" + if(C().foo2(10) != 10) return "fail" + if(C().bar2() != 239) return "fail" + if(C().bar2(10) != 10) return "fail" + if(reformat("", true, true, true, " ") != expected) return "fail" + if(reformat("", true, true, true) != expected) return "fail" + if(reformat("", true, true) != expected) return "fail" + if(reformat("", true) != expected) return "fail" + if(reformat("") != expected) return "fail" + return "OK" +} diff --git a/idea/testData/codegen/functions/namedargs.jet b/idea/testData/codegen/functions/namedargs.jet new file mode 100644 index 00000000000..e237c28f4d8 --- /dev/null +++ b/idea/testData/codegen/functions/namedargs.jet @@ -0,0 +1,19 @@ +fun reformat( + str : String, + normalizeCase : Boolean = true, + uppercaseFirstLetter : Boolean = true, + divideByCamelHumps : Boolean = false, + wordSeparator : String = " " +) = + (normalizeCase, uppercaseFirstLetter, divideByCamelHumps, wordSeparator) + +fun box() : String { + val expected = (true, true, false, " ") + if(reformat("", true, true, false, " ") != expected) return "fail" +// if(reformat(str="", wordSeparator=" ") != expected) return "fail" +// if(reformat("", true, true, false) != expected) return "fail" +// if(reformat("", true, true) != expected) return "fail" +// if(reformat("", true) != expected) return "fail" +// if(reformat("") != expected) return "fail" + return "OK" +} \ No newline at end of file diff --git a/idea/testData/codegen/functions/nothisnoclosure.jet b/idea/testData/codegen/functions/nothisnoclosure.jet new file mode 100644 index 00000000000..cb161d00ce0 --- /dev/null +++ b/idea/testData/codegen/functions/nothisnoclosure.jet @@ -0,0 +1,13 @@ +fun loop(times : Int) { + while(times > 0) { + val u : fun(value : Int) : Unit = { + System.out?.println(it) + } + u(times--) + } +} + +fun box() : String { + loop(5) + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java new file mode 100644 index 00000000000..5f79fc05480 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -0,0 +1,19 @@ +package org.jetbrains.jet.codegen; + +/** + * @author alex.tkachman + */ +public class FunctionGenTest extends CodegenTestCase { + public void testDefaultArgs() throws Exception { + blackBoxFile("functions/defaultargs.jet"); + } + + public void testNamedArgs() throws Exception { + blackBoxFile("functions/defaultargs.jet"); + } + + public void testNoThisNoClosure() throws Exception { + blackBoxFile("functions/nothisnoclosure.jet"); + System.out.println(generateToText()); + } +}