initial support for properties backed by instance fields; some dummy code to generate primary constructor
This commit is contained in:
@@ -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,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");
|
||||||
|
|||||||
Reference in New Issue
Block a user