From de50b2c191673a3a5f81f8f6ac52deb5b409cb5d Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Tue, 26 Apr 2011 11:18:51 +0400 Subject: [PATCH 01/17] Namespace properties can directly be accessed via backing field. --- idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java index f22d242d193..90b3eb05b76 100644 --- a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -85,9 +85,13 @@ public class PropertyCodegen { value = ((JetConstantExpression) initializer).getValue(); } } - int modifiers = Opcodes.ACC_PRIVATE; + final int modifiers; if (kind == OwnerKind.NAMESPACE) { - modifiers |= Opcodes.ACC_STATIC; + int access = isExternallyAccessible(p) ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE; + modifiers = access | Opcodes.ACC_STATIC; + } + else { + modifiers = Opcodes.ACC_PRIVATE; } v.visitField(modifiers, p.getName(), mapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value); } From 5c55f7d7d63dec6abbbc3ae9e5d6755dc46f6d27 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Thu, 28 Apr 2011 14:26:58 +0400 Subject: [PATCH 02/17] constructors are void --- idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index f97d8919a4f..a034e2abd97 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -193,7 +193,6 @@ public class JetTypeMapper { for (int i = 0; i < parameters.size(); i++) { parameterTypes[i] = mapType(parameters.get(i).getOutType()); } - Type returnType = mapType(descriptor.getUnsubstitutedReturnType()); return new Method("", Type.VOID_TYPE, parameterTypes); } From 1562de1347a12dbb04f9268afc3c2a5159c85c7b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 28 Apr 2011 12:49:56 +0200 Subject: [PATCH 03/17] map Nothing to void --- idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index a034e2abd97..2f2967804d5 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -79,7 +79,7 @@ public class JetTypeMapper { } public Type mapType(final JetType jetType) { - if (jetType.equals(JetStandardClasses.getUnitType())) { + if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { return Type.VOID_TYPE; } if (jetType.equals(standardLibrary.getIntType())) { From 6574cd98ed56daabb81eb635755f250d5254259a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 28 Apr 2011 13:29:42 +0200 Subject: [PATCH 04/17] test for stuff that Max has already implemented --- .../codegen/newInstanceDefaultConstructor.jet | 8 ++++++++ .../codegen/newInstanceExplicitConstructor.jet | 10 ++++++++++ .../org/jetbrains/jet/codegen/ClassGenTest.java | 12 +++++++++++- .../org/jetbrains/jet/codegen/CodegenTestCase.java | 6 +++++- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 idea/testData/codegen/newInstanceDefaultConstructor.jet create mode 100644 idea/testData/codegen/newInstanceExplicitConstructor.jet diff --git a/idea/testData/codegen/newInstanceDefaultConstructor.jet b/idea/testData/codegen/newInstanceDefaultConstructor.jet new file mode 100644 index 00000000000..84ef4b312e2 --- /dev/null +++ b/idea/testData/codegen/newInstanceDefaultConstructor.jet @@ -0,0 +1,8 @@ +class SimpleClass() { + fun foo() = 610 +} + +fun test() { + val c = new SimpleClass() + return c.foo() +} diff --git a/idea/testData/codegen/newInstanceExplicitConstructor.jet b/idea/testData/codegen/newInstanceExplicitConstructor.jet new file mode 100644 index 00000000000..f16447addad --- /dev/null +++ b/idea/testData/codegen/newInstanceExplicitConstructor.jet @@ -0,0 +1,10 @@ +class SimpleClass { + this() {} + + fun foo() = 610 +} + +fun test() { + val c = new SimpleClass() + return c.foo() +} diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 7cebefb5923..c0a019b0e24 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -24,10 +24,20 @@ public class ClassGenTest extends CodegenTestCase { checkInterface(aClass, List.class); } - private void checkInterface(Class aClass, Class ifs) { + private static void checkInterface(Class aClass, Class ifs) { for (Class anInterface : aClass.getInterfaces()) { if (anInterface == ifs) return; } fail(aClass.getName() + " must have " + ifs.getName() + " in its interfaces"); } + + public void testNewInstanceExplicitConstructor() throws Exception { + loadFile("newInstanceDefaultConstructor.jet"); + final Codegens codegens = generateClassesInFile(); + loadImplementationClass(codegens, "SimpleClass"); + Class ns = loadRootNamespaceClass(codegens); + final Method method = findMethodByName(ns, "test"); + final Integer returnValue = (Integer) method.invoke(null); + assertEquals(610, returnValue.intValue()); + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index ede78f23acd..ba65b5e702f 100644 --- a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -60,10 +60,14 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase { } protected Class generateNamespaceClass() { + Codegens state = generateClassesInFile(); + return loadRootNamespaceClass(state); + } + + protected Class loadRootNamespaceClass(Codegens state) { JetFile jetFile = (JetFile) myFixture.getFile(); final JetNamespace namespace = jetFile.getRootNamespace(); String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."); - Codegens state = generateClassesInFile(); return loadClass(fqName, state); } From bca39bf21f7612ccf9a96b5298139cfedee2942c Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Thu, 28 Apr 2011 19:38:14 +0400 Subject: [PATCH 05/17] Delegating to a super constructors, $delegate fields, $this field --- .../jetbrains/jet/codegen/ClassCodegen.java | 104 +++++++++++++++--- .../jet/codegen/ExpressionCodegen.java | 38 ++++++- .../jet/codegen/FunctionCodegen.java | 26 +---- .../jetbrains/jet/codegen/JetTypeMapper.java | 35 +++++- .../jet/codegen/NamespaceCodegen.java | 9 +- .../jet/codegen/PropertyCodegen.java | 16 --- .../jet/lang/resolve/BindingContext.java | 3 + .../jet/lang/resolve/BindingTraceContext.java | 12 ++ idea/testData/codegen/inheritance.jet | 11 ++ .../jetbrains/jet/codegen/ClassGenTest.java | 9 ++ 10 files changed, 199 insertions(+), 64 deletions(-) create mode 100644 idea/testData/codegen/inheritance.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index c62c45cd104..0347ac9a5a8 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -5,10 +5,7 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.types.ClassDescriptor; -import org.jetbrains.jet.lang.types.JetStandardLibrary; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.PropertyDescriptor; +import org.jetbrains.jet.lang.types.*; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -27,11 +24,15 @@ public class ClassCodegen { private final Project project; private final BindingContext bindingContext; private final Codegens factory; + private final JetTypeMapper typeMapper; public ClassCodegen(Project project, Codegens factory, BindingContext bindingContext) { this.project = project; this.factory = factory; this.bindingContext = bindingContext; + + final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); + typeMapper = new JetTypeMapper(standardLibrary, bindingContext); } public void generate(JetClass aClass) { @@ -158,31 +159,104 @@ public class ClassCodegen { } private void generatePrimaryConstructor(JetClass aClass, ClassVisitor v, OwnerKind kind) { + ConstructorDescriptor constructorDescriptor = bindingContext.getConstructorDescriptor(aClass); + if (constructorDescriptor == null) return; + + ClassDescriptor classDescriptor = bindingContext.getClassDescriptor(aClass); + + Method method = typeMapper.mapConstructorSignature(constructorDescriptor, kind); int flags = Opcodes.ACC_PUBLIC; // TODO - Method method = new Method("", Type.VOID_TYPE, new Type[0]); final MethodVisitor mv = v.visitMethod(flags, "", method.getDescriptor(), null, null); mv.visitCode(); + Type[] argTypes = method.getArgumentTypes(); + List paramDescrs = constructorDescriptor.getUnsubstitutedValueParameters(); + FrameMap frameMap = new FrameMap(); frameMap.enterTemp(); // this final InstructionAdapter iv = new InstructionAdapter(mv); - String superClass = getSuperClass(aClass, kind); - iv.load(0, Type.getType("L" + superClass + ";")); - iv.invokespecial(superClass, "", method.getDescriptor()); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, classDescriptor, kind); - final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext); - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, - typeMapper, Type.VOID_TYPE); - generateInitializers(aClass, kind, codegen, iv, typeMapper); + String classname = JetTypeMapper.jvmName(classDescriptor, kind); + if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { + String interfaceDesc = JetTypeMapper.jetInterfaceType(classDescriptor).getDescriptor(); + v.visitField(Opcodes.ACC_PRIVATE, "$this", interfaceDesc, /*TODO*/null, null); + iv.load(1, argTypes[0]); + iv.putfield(classname, "$this", interfaceDesc); + frameMap.enterTemp(); + } + + for (int i = 0; i < paramDescrs.size(); i++) { + ValueParameterDescriptor parameter = paramDescrs.get(i); + frameMap.enter(parameter, argTypes[i].getSize()); + } + + int n = 0; + for (JetDelegationSpecifier specifier : aClass.getDelegationSpecifiers()) { + boolean instanceOnStack = pushDelegateInstance(specifier, kind, codegen, iv, n); + if (instanceOnStack) { + JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + String delegateField = "$delegate_" + n; + v.visitField(Opcodes.ACC_PRIVATE, delegateField, JetTypeMapper.jvmNameForInterface(superClassDescriptor), /*TODO*/null, null); + iv.putfield(classname, delegateField, JetTypeMapper.jetInterfaceType(superClassDescriptor).getDescriptor()); + } + + n++; + } + + generateInitializers(aClass, kind, codegen, iv); iv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } - private void generateInitializers(JetClass aClass, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter iv, JetTypeMapper typeMapper) { + private boolean pushDelegateInstance(JetDelegationSpecifier specifier, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter v, int pos) { + boolean instanceOnStack = false; + if (specifier instanceof JetDelegatorToSuperCall) { + JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier; + ConstructorDescriptor constructorDescriptor = bindingContext.resolveSuperConstructor(superCall, this); + + ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration(); + boolean isDelegating = kind == OwnerKind.DELEGATING_IMPLEMENTATION; + Type type = isDelegating ? JetTypeMapper.jetDelegatingImplementationType(classDecl) : JetTypeMapper.jetImplementationType(classDecl); + + if (pos > 0) { + if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { + codegen.thisToStack(); + } + } + + Method method = typeMapper.mapConstructorSignature(constructorDescriptor, kind); + final Type[] argTypes = method.getArgumentTypes(); + List args = superCall.getValueArguments(); + for (int i = 0, argsSize = args.size(); i < argsSize; i++) { + JetArgument arg = args.get(i); + codegen.gen(arg.getArgumentExpression(), argTypes[i]); + } + + if (pos == 0) { + v.load(0, type); + } + else { + v.anew(type); + v.dup(); + instanceOnStack = true; + } + + v.invokespecial(type.getClassName(), "", method.getDescriptor()); + } + else if (specifier instanceof JetDelegatorByExpressionSpecifier) { + codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression()); + instanceOnStack = true; + } + + return instanceOnStack; + } + + private void generateInitializers(JetClass aClass, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter iv) { for (JetDeclaration declaration : aClass.getDeclarations()) { if (declaration instanceof JetProperty) { final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.getVariableDescriptor((JetProperty) declaration); @@ -201,7 +275,7 @@ public class ClassCodegen { private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) { final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext); + final FunctionCodegen functionCodegen = new FunctionCodegen(aClass, v, standardLibrary, bindingContext); final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen); for (JetDeclaration declaration : aClass.getDeclarations()) { diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 93e0df63f92..400cda7b555 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -35,13 +35,22 @@ public class ExpressionCodegen extends JetVisitor { private final FrameMap myMap; private final JetTypeMapper typeMapper; private final Type returnType; + private final ClassDescriptor contextType; + private final OwnerKind contextKind; private final BindingContext bindingContext; - public ExpressionCodegen(MethodVisitor v, BindingContext bindingContext, FrameMap myMap, JetTypeMapper typeMapper, - Type returnType) { + public ExpressionCodegen(MethodVisitor v, + BindingContext bindingContext, + FrameMap myMap, + JetTypeMapper typeMapper, + Type returnType, + ClassDescriptor contextType, + OwnerKind contextKind) { this.myMap = myMap; this.typeMapper = typeMapper; this.returnType = returnType; + this.contextType = contextType; + this.contextKind = contextKind; this.v = new InstructionAdapter(v); this.bindingContext = bindingContext; } @@ -51,7 +60,7 @@ public class ExpressionCodegen extends JetVisitor { expr.accept(this); } - private void gen(JetElement expr, Type type) { + public void gen(JetElement expr, Type type) { int oldStackDepth = myStack.size(); gen(expr); if (myStack.size() == oldStackDepth+1) { @@ -989,7 +998,7 @@ public class ExpressionCodegen extends JetVisitor { v.anew(type); v.dup(); - Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor); + Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); pushMethodArguments(expression, method); v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "", method.getDescriptor()); myStack.push(StackValue.onStack(type)); @@ -1031,6 +1040,27 @@ public class ExpressionCodegen extends JetVisitor { v.athrow(); } + @Override + public void visitThisExpression(JetThisExpression expression) { + thisToStack(); + } + + public void thisToStack() { + if (contextKind == OwnerKind.NAMESPACE) { + throw new UnsupportedOperationException("Cannot generate this expression in top level context"); + } + + if (contextKind == OwnerKind.IMPLEMENTATION) { + v.load(0, JetTypeMapper.jetImplementationType(contextType)); + } + else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) { + v.getfield(JetTypeMapper.jvmName(contextType, contextKind), "$this", JetTypeMapper.jetInterfaceType(contextType).getDescriptor()); + } + else { + throw new UnsupportedOperationException("Unknown kind: " + contextKind); + } + } + private static class CompilationException extends RuntimeException { } } diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 5516b2e7961..1573e81aebd 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -15,34 +15,18 @@ import java.util.List; * @author max */ public class FunctionCodegen { + private final JetDeclaration owner; private final ClassVisitor v; private final BindingContext bindingContext; - private final JetStandardLibrary standardLibrary; private final JetTypeMapper typeMapper; - public FunctionCodegen(ClassVisitor v, JetStandardLibrary standardLibrary, BindingContext bindingContext) { + public FunctionCodegen(JetDeclaration owner, ClassVisitor v, JetStandardLibrary standardLibrary, BindingContext bindingContext) { + this.owner = owner; this.v = v; this.bindingContext = bindingContext; - this.standardLibrary = standardLibrary; typeMapper = new JetTypeMapper(standardLibrary, bindingContext); } - public void genInNamespace(JetFunction f) { - gen(f, OwnerKind.NAMESPACE); - } - - public void genInInterface(JetFunction f) { - gen(f, OwnerKind.INTERFACE); - } - - public void genInImplementation(JetFunction f) { - - } - - public void genInDelegatingImplementation(JetFunction f) { - - } - public void gen(JetFunction f, OwnerKind kind) { Method method = typeMapper.mapSignature(f); List paramDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters(); @@ -59,6 +43,8 @@ public class FunctionCodegen { boolean isAbstract = kind == OwnerKind.INTERFACE || bodyExpression == null; if (isAbstract) flags |= Opcodes.ACC_ABSTRACT; + ClassDescriptor ownerClass = owner instanceof JetClass ? bindingContext.getClassDescriptor((JetClass) owner) : null; + final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); if (kind != OwnerKind.INTERFACE) { mv.visitCode(); @@ -74,7 +60,7 @@ public class FunctionCodegen { frameMap.enter(parameter, argTypes[i].getSize()); } - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, jvmSignature.getReturnType()); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, jvmSignature.getReturnType(), ownerClass, kind); bodyExpression.accept(codegen); generateReturn(mv, bodyExpression, codegen); mv.visitMaxs(0, 0); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 2f2967804d5..5c78baf0aa2 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -31,6 +31,22 @@ public class JetTypeMapper { return psiClass.getQualifiedName().replace(".", "/"); } + static String jvmName(ClassDescriptor jetClass, OwnerKind kind) { + switch (kind) { + + case INTERFACE: + return jvmNameForInterface(jetClass); + case IMPLEMENTATION: + return jvmNameForImplementation(jetClass); + case DELEGATING_IMPLEMENTATION: + return jvmNameForDelegatingImplementation(jetClass); + + default: + assert false : "Unsuitable kind"; + return "java/lang/Object"; + } + } + static Type psiClassType(PsiClass psiClass) { return Type.getType("L" + jvmName(psiClass) + ";"); } @@ -43,6 +59,10 @@ public class JetTypeMapper { return Type.getType("L" + jvmNameForImplementation(classDescriptor) + ";"); } + static Type jetDelegatingImplementationType(ClassDescriptor classDescriptor) { + return Type.getType("L" + jvmNameForDelegatingImplementation(classDescriptor) + ";"); + } + static String jvmName(JetNamespace namespace) { return NamespaceCodegen.getJVMClassName(namespace.getFQName()); } @@ -187,11 +207,18 @@ public class JetTypeMapper { return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType }); } - public Method mapConstructorSignature(ConstructorDescriptor descriptor) { + public Method mapConstructorSignature(ConstructorDescriptor descriptor, OwnerKind kind) { + boolean delegate = kind == OwnerKind.DELEGATING_IMPLEMENTATION; List parameters = descriptor.getUnsubstitutedValueParameters(); - Type[] parameterTypes = new Type[parameters.size()]; - for (int i = 0; i < parameters.size(); i++) { - parameterTypes[i] = mapType(parameters.get(i).getOutType()); + int count = parameters.size(); + int first = delegate ? 1 : 0; + Type[] parameterTypes = new Type[count + first]; + if (delegate) { + parameterTypes[0] = jetInterfaceType(descriptor.getContainingDeclaration()); + } + + for (int i = 0; i < count; i++) { + parameterTypes[i + first] = mapType(parameters.get(i).getOutType()); } return new Method("", Type.VOID_TYPE, parameterTypes); } diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 6bc2993f05c..8e9f45afcbb 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -41,7 +41,7 @@ public class NamespaceCodegen { BindingContext bindingContext = AnalyzingUtils.analyzeNamespace(namespace, ErrorHandler.THROW_EXCEPTION); final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext); + final FunctionCodegen functionCodegen = new FunctionCodegen(namespace, v, standardLibrary, bindingContext); final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen); final ClassCodegen classCodegen = codegens.forClass(bindingContext); @@ -51,10 +51,10 @@ public class NamespaceCodegen { for (JetDeclaration declaration : namespace.getDeclarations()) { if (declaration instanceof JetProperty) { - propertyCodegen.genInNamespace((JetProperty) declaration); + propertyCodegen.gen((JetProperty) declaration, OwnerKind.NAMESPACE); } else if (declaration instanceof JetFunction) { - functionCodegen.genInNamespace((JetFunction) declaration); + functionCodegen.gen((JetFunction) declaration, OwnerKind.NAMESPACE); } else if (declaration instanceof JetClass) { classCodegen.generate((JetClass) declaration); @@ -70,8 +70,7 @@ public class NamespaceCodegen { FrameMap frameMap = new FrameMap(); JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext); - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, - typeMapper, Type.VOID_TYPE); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, null, OwnerKind.NAMESPACE); for (JetDeclaration declaration : namespace.getDeclarations()) { if (declaration instanceof JetProperty) { diff --git a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 90b3eb05b76..c7025ab915c 100644 --- a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -29,22 +29,6 @@ public class PropertyCodegen { this.mapper = new JetTypeMapper(standardLibrary, context); } - public void genInNamespace(JetProperty p) { - gen(p, OwnerKind.NAMESPACE); - } - - public void genInInterface(JetProperty p) { - - } - - public void genInImplementation(JetProperty p) { - gen(p, OwnerKind.IMPLEMENTATION); - } - - public void genInDelegatingImplementation(JetProperty p) { - gen(p, OwnerKind.DELEGATING_IMPLEMENTATION); - } - public void gen(JetProperty p, OwnerKind kind) { final VariableDescriptor descriptor = context.getVariableDescriptor(p); if (!(descriptor instanceof PropertyDescriptor)) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 5872c5b59f7..0ffff7aef1f 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.resolve; import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ClassCodegen; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.*; @@ -29,4 +30,6 @@ public interface BindingContext { boolean isBlock(JetFunctionLiteralExpression expression); boolean isStatement(JetExpression expression); boolean hasBackingField(PropertyDescriptor propertyDescriptor); + + ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall, ClassCodegen classCodegen); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index b31ef953c21..d89c7d6e575 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.resolve; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.ClassCodegen; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.*; @@ -197,4 +198,15 @@ public class BindingTraceContext implements BindingContext, BindingTrace { } return fieldMentionedInAccessor.contains(propertyDescriptor); } + + public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall, ClassCodegen classCodegen) { + JetTypeReference typeReference = superCall.getTypeReference(); + if (typeReference == null) return null; + + JetTypeElement typeElement = typeReference.getTypeElement(); + if (!(typeElement instanceof JetUserType)) return null; + + DeclarationDescriptor descriptor = resolveReferenceExpression(((JetUserType) typeElement).getReferenceExpression()); + return descriptor instanceof ConstructorDescriptor ? (ConstructorDescriptor) descriptor : null; + } } diff --git a/idea/testData/codegen/inheritance.jet b/idea/testData/codegen/inheritance.jet new file mode 100644 index 00000000000..aea8e9fca4e --- /dev/null +++ b/idea/testData/codegen/inheritance.jet @@ -0,0 +1,11 @@ +class X(x : Int) {} +class Y(y : Int) {} + +class Point(x : Int, y : Int) : X(x), Y(y) {} + +class Abstract {} + +class P1(x : Int, y : Y) : Abstract, X(x), Y by y {} +class P2(x : Int, y : Y) : X(x), Abstract, Y by y {} +class P3(x : Int, y : Y) : X(x), Y by y, Abstract {} +class P4(x : Int, y : Y) : Y by y, Abstract, X(x) {} diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index c0a019b0e24..a8bd6ab5ed1 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -23,6 +23,15 @@ public class ClassGenTest extends CodegenTestCase { final Class aClass = loadClass("Foo", generateClassesInFile()); checkInterface(aClass, List.class); } + public void testArrayInheritance() throws Exception { + loadFile("inheritance.jet"); + System.out.println(generateToText()); + +/* + final Class aClass = loadClass("Foo", generateClassesInFile()); + checkInterface(aClass, List.class); +*/ + } private static void checkInterface(Class aClass, Class ifs) { for (Class anInterface : aClass.getInterfaces()) { From da6b4a959586bcaecf4aab2cc220935aebbe8609 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 28 Apr 2011 16:27:13 +0200 Subject: [PATCH 06/17] += for strings --- .../jet/codegen/ExpressionCodegen.java | 47 ++++++++++++++----- .../org/jetbrains/jet/codegen/StackValue.java | 22 +++++++-- idea/testData/codegen/fieldSetterPlusEq.jet | 7 +++ .../jet/codegen/NamespaceGenTest.java | 7 +++ .../jet/codegen/PropertyGenTest.java | 9 ++++ 5 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 idea/testData/codegen/fieldSetterPlusEq.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 400cda7b555..344fa1e5a9c 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -828,25 +828,44 @@ public class ExpressionCodegen extends JetVisitor { private void generateAugmentedAssignment(JetBinaryExpression expression) { DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); final JetExpression lhs = expression.getLeft(); - Type asmType = expressionType(lhs); - StackValue value = generateIntermediateValue(lhs); - value.dupReceiver(v); - value.put(asmType, v); - genToJVMStack(expression.getRight()); - v.visitInsn(asmType.getOpcode(opcodeForMethod(op.getName()))); - value.store(v); + Type lhsType = expressionType(lhs); + if (isNumberPrimitive(lhsType)) { + StackValue value = generateIntermediateValue(lhs); // receiver + value.dupReceiver(v, 0); // receiver receiver + value.put(lhsType, v); // receiver lhs + genToJVMStack(expression.getRight()); // receiver lhs rhs + v.visitInsn(lhsType.getOpcode(opcodeForMethod(op.getName()))); // receiver result + value.store(v); + } + else if ("java.lang.String".equals(lhsType.getClassName()) && op.getName().equals("plus")) { + generateStringBuilderConstructor(); // StringBuilder + StackValue value = generateIntermediateValue(lhs); // StringBuilder receiver + value.dupReceiver(v, 1); // receiver StringBuilder receiver + value.put(lhsType, v); // receiver StringBuilder value + invokeAppendMethod(lhsType); // receiver StringBuilder + invokeAppend(expression.getRight()); // receiver StringBuilder + v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;"); + value.store(v); + } + else { + throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented"); + } } private void generateConcatenation(JetBinaryExpression expression) { + generateStringBuilderConstructor(); + invokeAppend(expression.getLeft()); + invokeAppend(expression.getRight()); + v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;"); + myStack.push(StackValue.onStack(Type.getObjectType(CLASS_STRING))); + } + + private void generateStringBuilderConstructor() { Type type = Type.getObjectType(CLASS_STRING_BUILDER); v.anew(type); v.dup(); Method method = new Method("", Type.VOID_TYPE, new Type[0]); v.invokespecial(CLASS_STRING_BUILDER, method.getName(), method.getDescriptor()); - invokeAppend(expression.getLeft()); - invokeAppend(expression.getRight()); - v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;"); - myStack.push(StackValue.onStack(Type.getObjectType(CLASS_STRING))); } private void invokeAppend(final JetExpression expr) { @@ -860,6 +879,10 @@ public class ExpressionCodegen extends JetVisitor { } Type exprType = expressionType(expr); gen(expr, exprType); + invokeAppendMethod(exprType); + } + + private void invokeAppendMethod(Type exprType) { Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER), new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType}); v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor()); @@ -934,7 +957,7 @@ public class ExpressionCodegen extends JetVisitor { } } StackValue value = generateIntermediateValue(operand); - value.dupReceiver(v); + value.dupReceiver(v, 0); value.put(asmType, v); if (asmType == Type.LONG_TYPE) { v.aconst(Long.valueOf(increment)); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index ae3ea002e42..dc33d4e9daa 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -24,7 +24,7 @@ public abstract class StackValue { throw new UnsupportedOperationException("cannot store to value " + this); } - public void dupReceiver(InstructionAdapter v) { + public void dupReceiver(InstructionAdapter v, int below) { } public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { @@ -341,8 +341,13 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v) { - v.dup2(); // array and index + public void dupReceiver(InstructionAdapter v, int below) { + if (below == 1) { + v.dup2X1(); + } + else { + v.dup2(); // array and index + } } } @@ -364,8 +369,15 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v) { - if (!isStatic) v.dup(); + public void dupReceiver(InstructionAdapter v, int below) { + if (!isStatic) { + if (below == 1) { + v.dupX1(); + } + else { + v.dup(); + } + } } @Override diff --git a/idea/testData/codegen/fieldSetterPlusEq.jet b/idea/testData/codegen/fieldSetterPlusEq.jet new file mode 100644 index 00000000000..407adaf7f5e --- /dev/null +++ b/idea/testData/codegen/fieldSetterPlusEq.jet @@ -0,0 +1,7 @@ +var collector: String = "" + set(it) { $collector += it } + +fun append(s: String): String { + collector = s; + return collector; +} diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index abba7b42a1d..e3179f32814 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -259,6 +259,13 @@ public class NamespaceGenTest extends CodegenTestCase { assertEquals("jet Lang", main.invoke(null, "jet", " ", "Lang")); } + public void testStringPlusEq() throws Exception { + loadText("fun foo(s: String) { val result = s; result += s; return result; } "); + System.out.println(generateToText()); + final Method main = generateFunction(); + assertEquals("JarJar", main.invoke(null, "Jar")); + } + public void testStringCompare() throws Exception { loadText("fun foo(s1: String, s2: String) = s1 < s2"); System.out.println(generateToText()); diff --git a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index 34047039861..11377e758b2 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -81,6 +81,15 @@ public class PropertyGenTest extends CodegenTestCase { assertEquals(value, "IntelliJ IDEA"); } + public void testFieldSetterPlusEq() throws Exception { + loadFile("fieldSetterPlusEq.jet"); + System.out.println(generateToText()); + final Method method = generateFunction("append"); + method.invoke(null, "IntelliJ "); + String value = (String) method.invoke(null, "IDEA"); + assertEquals(value, "IntelliJ IDEA"); + } + public void testAccessorsWithoutBody() throws Exception { loadText("class AccessorsWithoutBody() { public var foo: Int = 349\n get\n private set\n fun setter() { foo = 610; } } "); final Class aClass = loadImplementationClass(generateClassesInFile(), "AccessorsWithoutBody"); From 89d7adbf73e6580690e20cbd56e11da6e1409dec Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 28 Apr 2011 18:24:16 +0200 Subject: [PATCH 07/17] generate for/in over java.lang.Iterable --- .../jet/codegen/ExpressionCodegen.java | 68 ++++++++++++++++++- idea/testData/codegen/for.jet | 4 +- .../jet/codegen/ControlStructuresTest.java | 5 +- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 344fa1e5a9c..b19daacfe70 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1,6 +1,8 @@ package org.jetbrains.jet.codegen; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.ProjectScope; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; @@ -15,6 +17,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; +import java.util.Iterator; import java.util.List; import java.util.Stack; @@ -26,6 +29,14 @@ public class ExpressionCodegen extends JetVisitor { private static final String CLASS_STRING = "java/lang/String"; private static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder"; private static final String CLASS_COMPARABLE = "java/lang/Comparable"; + private static final String CLASS_ITERABLE = "java/lang/Iterable"; + private static final String CLASS_ITERATOR = "java/util/Iterator"; + + private static final String ITERABLE_ITERATOR_DESCRIPTOR = "()Ljava/util/Iterator;"; + private static final String ITERATOR_HASNEXT_DESCRIPTOR = "()Z"; + private static final String ITERATOR_NEXT_DESCRIPTOR = "()Ljava/lang/Object;"; + + private static final Type ITERATOR_TYPE = Type.getType(Iterator.class); private final Stack