From d6611e495bfa003621e18ce54d4ade1eb315c8ee Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 21 Apr 2011 16:33:46 +0200 Subject: [PATCH] initial support for properties backed by instance fields; some dummy code to generate primary constructor --- .../jetbrains/jet/codegen/ClassCodegen.java | 31 +++++++++++--- .../jetbrains/jet/codegen/CodeGenUtil.java | 21 ---------- .../org/jetbrains/jet/codegen/Codegens.java | 7 ++-- .../jet/codegen/ExpressionCodegen.java | 42 ++++++++++++------- .../jetbrains/jet/codegen/JetTypeMapper.java | 15 ++++++- .../org/jetbrains/jet/codegen/StackValue.java | 16 +++---- idea/testData/codegen/privateVar.jet | 2 +- .../jet/codegen/PropertyGenTest.java | 1 + 8 files changed, 81 insertions(+), 54 deletions(-) delete mode 100644 idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index e98c3d2e415..ee2c38710ef 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -9,9 +9,12 @@ import org.jetbrains.jet.lang.types.ClassDescriptor; import org.jetbrains.jet.lang.types.JetStandardLibrary; 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.commons.InstructionAdapter; +import org.objectweb.asm.commons.Method; -import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -41,7 +44,7 @@ public class ClassCodegen { Set superInterfaces = getSuperInterfaces(aClass); - String fqName = CodeGenUtil.getInternalInterfaceName(descriptor); + String fqName = JetTypeMapper.jvmNameForInterface(descriptor); ClassVisitor v = factory.forClassInterface(descriptor); v.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, @@ -64,12 +67,14 @@ public class ClassCodegen { ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor); v.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, - CodeGenUtil.getInternalImplementationName(descriptor), + JetTypeMapper.jvmNameForImplementation(descriptor), null, superClass, - new String[] {CodeGenUtil.getInternalInterfaceName(descriptor)} + new String[] {JetTypeMapper.jvmNameForInterface(descriptor)} ); + generatePrimaryConstructor(aClass, v, kind); + generateClassBody(aClass, v, kind); v.visitEnd(); @@ -107,7 +112,7 @@ public class ClassCodegen { if (superInterfaces.size() > 0) { ClassDescriptor first = superInterfaces.iterator().next(); - return kind == OwnerKind.IMPLEMENTATION ? CodeGenUtil.getInternalImplementationName(first) : CodeGenUtil.getInternalDelegatingImplementationName(first); + return kind == OwnerKind.IMPLEMENTATION ? JetTypeMapper.jvmNameForImplementation(first) : JetTypeMapper.jvmNameForDelegatingImplementation(first); } return "java/lang/Object"; @@ -145,12 +150,26 @@ public class ClassCodegen { } } else { - superInterfaces.add(CodeGenUtil.getInternalInterfaceName(superClassDescriptor)); + superInterfaces.add(JetTypeMapper.jvmNameForInterface(superClassDescriptor)); } } return superInterfaces; } + private void generatePrimaryConstructor(JetClass aClass, ClassVisitor v, OwnerKind 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(); + final InstructionAdapter iv = new InstructionAdapter(mv); + String superClass = getSuperClass(aClass, kind); + iv.load(0, Type.getType("L" + superClass + ";")); + iv.invokespecial(superClass, "", method.getDescriptor()); + iv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) { final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext); diff --git a/idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java b/idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java deleted file mode 100644 index be0ffdae816..00000000000 --- a/idea/src/org/jetbrains/jet/codegen/CodeGenUtil.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.jetbrains.jet.codegen; - -import org.jetbrains.jet.lang.types.ClassDescriptor; -import org.jetbrains.jet.resolve.DescriptorUtil; - -/** - * @author max - */ -public class CodeGenUtil { - public static String getInternalInterfaceName(ClassDescriptor descriptor) { - return DescriptorUtil.getFQName(descriptor).replace('.', '/'); - } - - public static String getInternalImplementationName(ClassDescriptor descriptor) { - return getInternalInterfaceName(descriptor) + "$$Impl"; - } - - public static String getInternalDelegatingImplementationName(ClassDescriptor descriptor) { - return getInternalInterfaceName(descriptor) + "$$DImpl"; - } -} diff --git a/idea/src/org/jetbrains/jet/codegen/Codegens.java b/idea/src/org/jetbrains/jet/codegen/Codegens.java index 44b6cdf3a4f..9e4aa814bd7 100644 --- a/idea/src/org/jetbrains/jet/codegen/Codegens.java +++ b/idea/src/org/jetbrains/jet/codegen/Codegens.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.ClassDescriptor; @@ -45,7 +44,7 @@ public class Codegens { } public ClassVisitor forClassInterface(ClassDescriptor aClass) { - return newVisitor(CodeGenUtil.getInternalInterfaceName(aClass) + ".class"); + return newVisitor(JetTypeMapper.jvmNameForInterface(aClass) + ".class"); } public ClassCodegen forClass(BindingContext bindingContext) { @@ -53,11 +52,11 @@ public class Codegens { } public ClassVisitor forClassImplementation(ClassDescriptor aClass) { - return newVisitor(CodeGenUtil.getInternalImplementationName(aClass) + ".class"); + return newVisitor(JetTypeMapper.jvmNameForImplementation(aClass) + ".class"); } public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) { - return newVisitor(CodeGenUtil.getInternalDelegatingImplementationName(aClass) + ".class"); + return newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class"); } public NamespaceCodegen forNamespace(JetNamespace namespace) { diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 8e9f88d72ec..a43d5f73632 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -372,25 +372,36 @@ public class ExpressionCodegen extends JetVisitor { } else if (descriptor instanceof PropertyDescriptor) { final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + String owner; + boolean isStatic; if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { JetNamespace ns = (JetNamespace) bindingContext.getDeclarationPsiElement(descriptor.getContainingDeclaration()); - String owner = JetTypeMapper.jvmName(ns); - final JetType outType = ((VariableDescriptor) descriptor).getOutType(); - Method getter; - Method setter; - if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { - getter = null; - setter = null; - } - else { - getter = typeMapper.mapGetterSignature(propertyDescriptor); - setter = typeMapper.mapSetterSignature(propertyDescriptor); - } - myStack.push(StackValue.property(descriptor.getName(), owner, typeMapper.mapType(outType), getter, setter)); + owner = JetTypeMapper.jvmName(ns); + isStatic = true; + } + else if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration(); + owner = JetTypeMapper.jvmNameForImplementation(classDescriptor); + isStatic = false; } else { - throw new UnsupportedOperationException("don't know how to generate non-namespace property reference " + descriptor); + throw new UnsupportedOperationException("don't know how to generate property reference with parent " + descriptor.getContainingDeclaration()); } + final JetType outType = ((VariableDescriptor) descriptor).getOutType(); + Method getter; + Method setter; + if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { + getter = null; + setter = null; + } + else { + getter = typeMapper.mapGetterSignature(propertyDescriptor); + setter = typeMapper.mapSetterSignature(propertyDescriptor); + } + if (!isStatic) { + ensureReceiverOnStack(expression); + } + myStack.push(StackValue.property(descriptor.getName(), owner, typeMapper.mapType(outType), isStatic, getter, setter)); } else { throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); @@ -489,6 +500,9 @@ public class ExpressionCodegen extends JetVisitor { myStack.pop().put(TYPE_OBJECT, v); } } + else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) { + v.load(0, TYPE_OBJECT); // TODO hope it works; really need more checks here :) + } } private void pushMethodArguments(JetCall expression, Method method) { diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index ba0c0ade047..a751c002563 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.resolve.DescriptorUtil; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; @@ -38,6 +39,18 @@ public class JetTypeMapper { return NamespaceCodegen.getJVMClassName(namespace.getFQName()); } + public static String jvmNameForInterface(ClassDescriptor descriptor) { + return DescriptorUtil.getFQName(descriptor).replace('.', '/'); + } + + public static String jvmNameForImplementation(ClassDescriptor descriptor) { + return jvmNameForInterface(descriptor) + "$$Impl"; + } + + public static String jvmNameForDelegatingImplementation(ClassDescriptor descriptor) { + return jvmNameForInterface(descriptor) + "$$DImpl"; + } + public Type mapType(final JetType jetType) { if (jetType.equals(JetStandardClasses.getUnitType())) { return Type.VOID_TYPE; @@ -112,7 +125,7 @@ public class JetTypeMapper { if (declaration instanceof PsiClass) { return psiClassType((PsiClass) declaration); } - return Type.getObjectType(CodeGenUtil.getInternalInterfaceName((ClassDescriptor) descriptor)); + return Type.getObjectType(jvmNameForInterface((ClassDescriptor) descriptor)); } throw new UnsupportedOperationException("Unknown type " + jetType); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 06c70534c29..ae3ea002e42 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -71,8 +71,8 @@ public abstract class StackValue { return new Field(type, owner, name, isStatic); } - public static StackValue property(String name, String owner, Type type, Method getter, Method setter) { - return new Property(name, owner, getter, setter, type); + public static StackValue property(String name, String owner, Type type, boolean isStatic, Method getter, Method setter) { + return new Property(name, owner, getter, setter, isStatic, type); } private static void box(final Type type, InstructionAdapter v) { @@ -379,32 +379,34 @@ public abstract class StackValue { private final String owner; private final Method getter; private final Method setter; + private final boolean isStatic; - public Property(String name, String owner, Method getter, Method setter, Type type) { + public Property(String name, String owner, Method getter, Method setter, boolean aStatic, Type type) { super(type); this.name = name; this.owner = owner; this.getter = getter; this.setter = setter; + isStatic = aStatic; } @Override public void put(Type type, InstructionAdapter v) { if (getter == null) { - v.visitFieldInsn(Opcodes.GETSTATIC, owner, name, type.getDescriptor()); + v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, type.getDescriptor()); } else { - v.invokestatic(owner, getter.getName(), getter.getDescriptor()); + v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, owner, getter.getName(), getter.getDescriptor()); } } @Override public void store(InstructionAdapter v) { if (setter == null) { - v.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, type.getDescriptor()); + v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, type.getDescriptor()); } else { - v.invokestatic(owner, setter.getName(), setter.getDescriptor()); + v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor()); } } } diff --git a/idea/testData/codegen/privateVar.jet b/idea/testData/codegen/privateVar.jet index 9a62a4ae075..64cd7816373 100644 --- a/idea/testData/codegen/privateVar.jet +++ b/idea/testData/codegen/privateVar.jet @@ -1,6 +1,6 @@ class PrivateVar { private var x = 0; - fun setValueOfX(val: Int) { x = val } + fun setValueOfX(aValue: Int) { x = aValue } fun getValueOfX() = x } diff --git a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index b4d3dc2bc8f..96e91d60eba 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -20,6 +20,7 @@ public class PropertyGenTest extends CodegenTestCase { public void testPrivateVar() throws Exception { loadFile("privateVar.jet"); + System.out.println(generateToText()); final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVar"); final Object instance = aClass.newInstance(); Method setter = findMethodByName(aClass, "setValueOfX");