From c62bbdc5df2f783789d36326a817700cd997aab2 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 29 Jan 2012 16:19:47 +0300 Subject: [PATCH] local functions --- .../jetbrains/jet/codegen/ClosureCodegen.java | 4 +- .../jetbrains/jet/codegen/CodegenUtil.java | 2 +- .../jet/codegen/ExpressionCodegen.java | 111 +++++++++++------- .../jetbrains/jet/codegen/JetTypeMapper.java | 4 + .../codegen/functions/localFunction.kt | 31 +++++ .../jet/codegen/FunctionGenTest.java | 4 + 6 files changed, 110 insertions(+), 46 deletions(-) create mode 100644 compiler/testData/codegen/functions/localFunction.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 75a7a56eaeb..1de993847c0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -83,7 +83,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { return state.getTypeMapper().mapSignature("invoke", fd); } - public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) { + public GeneratedAnonymousClassDescriptor gen(JetExpression fun) { final Pair nameAndVisitor = state.forAnonymousSubclass(fun); final FunctionDescriptor funDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, fun); @@ -115,7 +115,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { generateBridge(name, funDescriptor, fun, cv); - captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); + captureThis = generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun); ClassDescriptor thisDescriptor = context.getThisDescriptor(); final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType()); if (enclosingType == null) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index c500e640bc1..2ce02718eb0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -88,7 +88,7 @@ public class CodegenUtil { return hasDerivedTypeInfoField(type); } - public static NamedFunctionDescriptor createInvoke(ExpressionAsFunctionDescriptor fd) { + public static NamedFunctionDescriptor createInvoke(FunctionDescriptor fd) { int arity = fd.getValueParameters().size(); NamedFunctionDescriptorImpl invokeDescriptor = new NamedFunctionDescriptorImpl( fd.getExpectedThisObject().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity), diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index cac967c2cc0..457efc8c24c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -161,11 +161,6 @@ public class ExpressionCodegen extends JetVisitor { throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented"); } - @Override - public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) { - throw new UnsupportedOperationException("Codegen for local functions is not yet implemented"); - } - @Override public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) { final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); @@ -712,6 +707,17 @@ public class ExpressionCodegen extends JetVisitor { return generateBlock(statements); } + @Override + public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) { + assert data == StackValue.none(); + StackValue closure = genClosure(function); + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function); + int index = myFrameMap.getIndex(descriptor); + closure.put(TYPE_OBJECT, v); + v.store(index, TYPE_OBJECT); + return StackValue.none(); + } + @Override public StackValue visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, StackValue receiver) { //noinspection ConstantConditions @@ -720,40 +726,44 @@ public class ExpressionCodegen extends JetVisitor { return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements()); } else { - ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context); - final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression); - - if(closureCodegen.isConst()) { - v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";"); - } - else { - v.anew(Type.getObjectType(closure.getClassname())); - v.dup(); - - final Method cons = closure.getConstructor(); - - int k = 0; - if (closure.isCaptureThis()) { - k++; - v.load(0, TYPE_OBJECT); - } - - if (closure.isCaptureReceiver() != null) { - k++; - v.load(context.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor ? 0: 1, closure.isCaptureReceiver()); - } - - for (int i = 0; i < closure.getArgs().size(); i++) { - StackValue arg = closure.getArgs().get(i); - arg.put(cons.getArgumentTypes()[i+k], v); - } - - v.invokespecial(closure.getClassname(), "", cons.getDescriptor()); - } - return StackValue.onStack(Type.getObjectType(closure.getClassname())); + return genClosure(expression); } } + private StackValue genClosure(JetExpression expression) { + ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context); + final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression); + + if(closureCodegen.isConst()) { + v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";"); + } + else { + v.anew(Type.getObjectType(closure.getClassname())); + v.dup(); + + final Method cons = closure.getConstructor(); + + int k = 0; + if (closure.isCaptureThis()) { + k++; + v.load(0, TYPE_OBJECT); + } + + if (closure.isCaptureReceiver() != null) { + k++; + v.load(context.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor ? 0: 1, closure.isCaptureReceiver()); + } + + for (int i = 0; i < closure.getArgs().size(); i++) { + StackValue arg = closure.getArgs().get(i); + arg.put(cons.getArgumentTypes()[i+k], v); + } + + v.invokespecial(closure.getClassname(), "", cons.getDescriptor()); + } + return StackValue.onStack(Type.getObjectType(closure.getClassname())); + } + @Override public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) { ObjectOrClosureCodegen closureCodegen = new ObjectOrClosureCodegen(this, context, state); @@ -811,6 +821,11 @@ public class ExpressionCodegen extends JetVisitor { final Type type = sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getOutType()); myFrameMap.enter(variableDescriptor, type.getSize()); } + + if(statement instanceof JetNamedFunction) { + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, statement); + myFrameMap.enter(descriptor, 1); + } } StackValue answer = StackValue.none(); @@ -831,6 +846,11 @@ public class ExpressionCodegen extends JetVisitor { v.mark(blockEnd); for (JetElement statement : statements) { + if(statement instanceof JetNamedFunction) { + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, statement); + myFrameMap.leave(descriptor); + } + if (statement instanceof JetProperty) { JetProperty var = (JetProperty) statement; VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var); @@ -946,13 +966,18 @@ public class ExpressionCodegen extends JetVisitor { int index = lookupLocal(descriptor); if (index >= 0) { - Type sharedVarType = typeMapper.getSharedVarType(descriptor); - final JetType outType = ((VariableDescriptor) descriptor).getOutType(); - if(sharedVarType != null) { - return StackValue.shared(index, asmType(outType)); + if(descriptor instanceof VariableDescriptor) { + Type sharedVarType = typeMapper.getSharedVarType(descriptor); + final JetType outType = ((VariableDescriptor) descriptor).getOutType(); + if(sharedVarType != null) { + return StackValue.shared(index, asmType(outType)); + } + else { + return StackValue.local(index, asmType(outType)); + } } else { - return StackValue.local(index, asmType(outType)); + return StackValue.local(index, TYPE_OBJECT); } } else if (descriptor instanceof PropertyDescriptor) { @@ -1266,8 +1291,8 @@ public class ExpressionCodegen extends JetVisitor { assert !superCall; callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd); } - else if (fd instanceof ExpressionAsFunctionDescriptor) { - NamedFunctionDescriptor invoke = CodegenUtil.createInvoke((ExpressionAsFunctionDescriptor) fd); + else if (fd instanceof ExpressionAsFunctionDescriptor || (fd instanceof NamedFunctionDescriptor && fd.getContainingDeclaration() instanceof FunctionDescriptor)) { + NamedFunctionDescriptor invoke = CodegenUtil.createInvoke((FunctionDescriptor) fd); callableMethod = ClosureCodegen.asCallableMethod(invoke); } else if (fd instanceof FunctionDescriptor) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index a9174fb44a3..5f21e8f80f3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -827,6 +827,10 @@ public class JetTypeMapper { if(descriptor instanceof PropertyDescriptor) { return StackValue.sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType())); } + else if (descriptor instanceof NamedFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) { + PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); + return Type.getObjectType(classNameForAnonymousClass((JetElement) psiElement)); + } else if (descriptor instanceof FunctionDescriptor) { return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType())); } diff --git a/compiler/testData/codegen/functions/localFunction.kt b/compiler/testData/codegen/functions/localFunction.kt new file mode 100644 index 00000000000..be1e98e6dde --- /dev/null +++ b/compiler/testData/codegen/functions/localFunction.kt @@ -0,0 +1,31 @@ +fun box() : String { + var seed = 0 + fun local(x: Int) { + fun deep() { + seed += x + } + fun deep2(x : Int) { + seed += x + } + fun Int.iter() { + seed += this + } + + deep() + deep2(-x) + x.iter() + seed += x + } + + for(i in 1..5) { + fun Int.iter() { + seed += this + } + + local(i) + (-i).iter() + } + + + return if(seed == 15) "OK" else seed.toString() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 7fcf625cc6f..bb27eff7ef9 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -48,4 +48,8 @@ public class FunctionGenTest extends CodegenTestCase { public void testFunction () throws InvocationTargetException, IllegalAccessException { blackBoxFile("functions/functionExpression.jet"); } + + public void testLocalFunction () throws InvocationTargetException, IllegalAccessException { + blackBoxFile("functions/localFunction.kt"); + } }