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.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<String> 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("<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) {
|
||||
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
|
||||
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;
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user