initial support for properties backed by instance fields; some dummy code to generate primary constructor

This commit is contained in:
Dmitry Jemerov
2011-04-21 16:33:46 +02:00
parent 433c073778
commit d6611e495b
8 changed files with 81 additions and 54 deletions
@@ -9,9 +9,12 @@ import org.jetbrains.jet.lang.types.ClassDescriptor;
import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; 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.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -41,7 +44,7 @@ public class ClassCodegen {
Set<String> superInterfaces = getSuperInterfaces(aClass); Set<String> superInterfaces = getSuperInterfaces(aClass);
String fqName = CodeGenUtil.getInternalInterfaceName(descriptor); String fqName = JetTypeMapper.jvmNameForInterface(descriptor);
ClassVisitor v = factory.forClassInterface(descriptor); ClassVisitor v = factory.forClassInterface(descriptor);
v.visit(Opcodes.V1_6, v.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, 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); ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor);
v.visit(Opcodes.V1_6, v.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC,
CodeGenUtil.getInternalImplementationName(descriptor), JetTypeMapper.jvmNameForImplementation(descriptor),
null, null,
superClass, superClass,
new String[] {CodeGenUtil.getInternalInterfaceName(descriptor)} new String[] {JetTypeMapper.jvmNameForInterface(descriptor)}
); );
generatePrimaryConstructor(aClass, v, kind);
generateClassBody(aClass, v, kind); generateClassBody(aClass, v, kind);
v.visitEnd(); v.visitEnd();
@@ -107,7 +112,7 @@ public class ClassCodegen {
if (superInterfaces.size() > 0) { if (superInterfaces.size() > 0) {
ClassDescriptor first = superInterfaces.iterator().next(); 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"; return "java/lang/Object";
@@ -145,12 +150,26 @@ public class ClassCodegen {
} }
} }
else { else {
superInterfaces.add(CodeGenUtil.getInternalInterfaceName(superClassDescriptor)); superInterfaces.add(JetTypeMapper.jvmNameForInterface(superClassDescriptor));
} }
} }
return superInterfaces; return superInterfaces;
} }
private void generatePrimaryConstructor(JetClass aClass, ClassVisitor v, OwnerKind kind) {
int flags = Opcodes.ACC_PUBLIC; // TODO
Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
final MethodVisitor mv = v.visitMethod(flags, "<init>", 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, "<init>", method.getDescriptor());
iv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) { private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) {
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext); final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext);
@@ -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";
}
}
@@ -1,7 +1,6 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.project.Project; 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.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.ClassDescriptor; import org.jetbrains.jet.lang.types.ClassDescriptor;
@@ -45,7 +44,7 @@ public class Codegens {
} }
public ClassVisitor forClassInterface(ClassDescriptor aClass) { public ClassVisitor forClassInterface(ClassDescriptor aClass) {
return newVisitor(CodeGenUtil.getInternalInterfaceName(aClass) + ".class"); return newVisitor(JetTypeMapper.jvmNameForInterface(aClass) + ".class");
} }
public ClassCodegen forClass(BindingContext bindingContext) { public ClassCodegen forClass(BindingContext bindingContext) {
@@ -53,11 +52,11 @@ public class Codegens {
} }
public ClassVisitor forClassImplementation(ClassDescriptor aClass) { public ClassVisitor forClassImplementation(ClassDescriptor aClass) {
return newVisitor(CodeGenUtil.getInternalImplementationName(aClass) + ".class"); return newVisitor(JetTypeMapper.jvmNameForImplementation(aClass) + ".class");
} }
public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) { public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) {
return newVisitor(CodeGenUtil.getInternalDelegatingImplementationName(aClass) + ".class"); return newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class");
} }
public NamespaceCodegen forNamespace(JetNamespace namespace) { public NamespaceCodegen forNamespace(JetNamespace namespace) {
@@ -372,25 +372,36 @@ public class ExpressionCodegen extends JetVisitor {
} }
else if (descriptor instanceof PropertyDescriptor) { else if (descriptor instanceof PropertyDescriptor) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
String owner;
boolean isStatic;
if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
JetNamespace ns = (JetNamespace) bindingContext.getDeclarationPsiElement(descriptor.getContainingDeclaration()); JetNamespace ns = (JetNamespace) bindingContext.getDeclarationPsiElement(descriptor.getContainingDeclaration());
String owner = JetTypeMapper.jvmName(ns); owner = JetTypeMapper.jvmName(ns);
final JetType outType = ((VariableDescriptor) descriptor).getOutType(); isStatic = true;
Method getter; }
Method setter; else if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { ClassDescriptor classDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration();
getter = null; owner = JetTypeMapper.jvmNameForImplementation(classDescriptor);
setter = null; isStatic = false;
}
else {
getter = typeMapper.mapGetterSignature(propertyDescriptor);
setter = typeMapper.mapSetterSignature(propertyDescriptor);
}
myStack.push(StackValue.property(descriptor.getName(), owner, typeMapper.mapType(outType), getter, setter));
} }
else { 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 { else {
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); 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); 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) { private void pushMethodArguments(JetCall expression, Method method) {
@@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.resolve.DescriptorUtil;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method; import org.objectweb.asm.commons.Method;
@@ -38,6 +39,18 @@ public class JetTypeMapper {
return NamespaceCodegen.getJVMClassName(namespace.getFQName()); 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) { public Type mapType(final JetType jetType) {
if (jetType.equals(JetStandardClasses.getUnitType())) { if (jetType.equals(JetStandardClasses.getUnitType())) {
return Type.VOID_TYPE; return Type.VOID_TYPE;
@@ -112,7 +125,7 @@ public class JetTypeMapper {
if (declaration instanceof PsiClass) { if (declaration instanceof PsiClass) {
return psiClassType((PsiClass) declaration); return psiClassType((PsiClass) declaration);
} }
return Type.getObjectType(CodeGenUtil.getInternalInterfaceName((ClassDescriptor) descriptor)); return Type.getObjectType(jvmNameForInterface((ClassDescriptor) descriptor));
} }
throw new UnsupportedOperationException("Unknown type " + jetType); throw new UnsupportedOperationException("Unknown type " + jetType);
@@ -71,8 +71,8 @@ public abstract class StackValue {
return new Field(type, owner, name, isStatic); return new Field(type, owner, name, isStatic);
} }
public static StackValue property(String name, String owner, Type type, Method getter, Method setter) { public static StackValue property(String name, String owner, Type type, boolean isStatic, Method getter, Method setter) {
return new Property(name, owner, getter, setter, type); return new Property(name, owner, getter, setter, isStatic, type);
} }
private static void box(final Type type, InstructionAdapter v) { private static void box(final Type type, InstructionAdapter v) {
@@ -379,32 +379,34 @@ public abstract class StackValue {
private final String owner; private final String owner;
private final Method getter; private final Method getter;
private final Method setter; 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); super(type);
this.name = name; this.name = name;
this.owner = owner; this.owner = owner;
this.getter = getter; this.getter = getter;
this.setter = setter; this.setter = setter;
isStatic = aStatic;
} }
@Override @Override
public void put(Type type, InstructionAdapter v) { public void put(Type type, InstructionAdapter v) {
if (getter == null) { if (getter == null) {
v.visitFieldInsn(Opcodes.GETSTATIC, owner, name, type.getDescriptor()); v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, type.getDescriptor());
} }
else { else {
v.invokestatic(owner, getter.getName(), getter.getDescriptor()); v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, owner, getter.getName(), getter.getDescriptor());
} }
} }
@Override @Override
public void store(InstructionAdapter v) { public void store(InstructionAdapter v) {
if (setter == null) { if (setter == null) {
v.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, type.getDescriptor()); v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, type.getDescriptor());
} }
else { else {
v.invokestatic(owner, setter.getName(), setter.getDescriptor()); v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor());
} }
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
class PrivateVar { class PrivateVar {
private var x = 0; private var x = 0;
fun setValueOfX(val: Int) { x = val } fun setValueOfX(aValue: Int) { x = aValue }
fun getValueOfX() = x fun getValueOfX() = x
} }
@@ -20,6 +20,7 @@ public class PropertyGenTest extends CodegenTestCase {
public void testPrivateVar() throws Exception { public void testPrivateVar() throws Exception {
loadFile("privateVar.jet"); loadFile("privateVar.jet");
System.out.println(generateToText());
final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVar"); final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVar");
final Object instance = aClass.newInstance(); final Object instance = aClass.newInstance();
Method setter = findMethodByName(aClass, "setValueOfX"); Method setter = findMethodByName(aClass, "setValueOfX");