From 17f7ea9292a120e82e3509fb0d1f52d4f254a5c6 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Sun, 29 May 2011 18:40:56 +0400 Subject: [PATCH] refactoring: extract ClassBodyCodegen out of ClassCodegen, separate subclasses for interface and implementation --- .../jet/codegen/ClassBodyCodegen.java | 83 ++++ .../jetbrains/jet/codegen/ClassCodegen.java | 419 +----------------- .../codegen/ImplementationBodyCodegen.java | 339 ++++++++++++++ .../jet/codegen/InterfaceBodyCodegen.java | 76 ++++ .../jet/lang/resolve/BindingContext.java | 2 +- .../jet/lang/resolve/BindingTraceContext.java | 5 +- .../tests/org/jetbrains/jet/JetTestUtils.java | 2 +- 7 files changed, 508 insertions(+), 418 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java create mode 100644 idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java create mode 100644 idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java diff --git a/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java new file mode 100644 index 00000000000..8b70b2f2ad5 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -0,0 +1,83 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; + +/** + * @author max + * @author yole + */ +public abstract class ClassBodyCodegen { + protected final BindingContext bindingContext; + protected final JetStandardLibrary stdlib; + protected final JetTypeMapper typeMapper; + protected final JetClass myClass; + protected final OwnerKind kind; + protected final ClassDescriptor descriptor; + protected final ClassVisitor v; + + public ClassBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClass aClass, OwnerKind kind, ClassVisitor v) { + this.bindingContext = bindingContext; + this.stdlib = stdlib; + this.typeMapper = new JetTypeMapper(stdlib, bindingContext); + descriptor = bindingContext.getClassDescriptor(aClass); + myClass = aClass; + this.kind = kind; + this.v = v; + } + + public void generate() { + generateDeclaration(); + + generateSyntheticParts(); + + generateClassBody(); + + v.visitEnd(); + } + + protected abstract void generateDeclaration(); + + protected void generateSyntheticParts() { + } + + private void generateClassBody() { + final FunctionCodegen functionCodegen = new FunctionCodegen(myClass, v, stdlib, bindingContext); + final PropertyCodegen propertyCodegen = new PropertyCodegen(v, stdlib, bindingContext, functionCodegen); + + for (JetDeclaration declaration : myClass.getDeclarations()) { + if (declaration instanceof JetProperty) { + propertyCodegen.gen((JetProperty) declaration, kind); + } + else if (declaration instanceof JetFunction) { + try { + functionCodegen.gen((JetFunction) declaration, kind); + } catch (RuntimeException e) { + throw new RuntimeException("Error generating method "+ myClass.getName() + "." + declaration.getName(), e); + } + } + } + + for (JetParameter p : myClass.getPrimaryConstructorParameters()) { + if (p.getValOrVarNode() != null) { + PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p); + if (propertyDescriptor != null) { + propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); + if (propertyDescriptor.isVar()) { + propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); + } + + if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && bindingContext.hasBackingField(propertyDescriptor)) { + v.visitField(Opcodes.ACC_PRIVATE, p.getName(), typeMapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null); + } + } + } + } + } + +} diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index b739270eee1..4bf390d8532 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -1,24 +1,14 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.resolve.BindingContext; 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.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; /** * @author max @@ -51,399 +41,16 @@ public class ClassCodegen { } private void generateInterface(JetClass aClass) { - ClassDescriptor descriptor = bindingContext.getClassDescriptor(aClass); - - Set superInterfaces = getSuperInterfaces(aClass); - - String fqName = JetTypeMapper.jvmNameForInterface(descriptor); - ClassVisitor v = factory.forClassInterface(descriptor); - v.visit(Opcodes.V1_6, - Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, - fqName, - null, - "java/lang/Object", - superInterfaces.toArray(new String[superInterfaces.size()]) - ); - - generateClassBody(aClass, v, OwnerKind.INTERFACE); - - v.visitEnd(); + final ClassVisitor visitor = factory.forClassInterface(bindingContext.getClassDescriptor(aClass)); + new InterfaceBodyCodegen(bindingContext, JetStandardLibrary.getJetStandardLibrary(project), aClass, visitor).generate(); } private void generateImplementation(JetClass aClass, OwnerKind kind) { ClassDescriptor descriptor = bindingContext.getClassDescriptor(aClass); - - String superClass = getSuperClass(aClass, kind); - ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor); - final String defaultInterfaceName = JetTypeMapper.jvmNameForInterface(descriptor); - v.visit(Opcodes.V1_6, - Opcodes.ACC_PUBLIC, - JetTypeMapper.jetJvmName(descriptor, kind), - null, - superClass, - new String[] { "jet/JetObject", defaultInterfaceName} - ); - - int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC; - v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); - - generateStaticInitializer(descriptor, v); - - generatePrimaryConstructor(aClass, v, kind); - - generateGetTypeInfo(descriptor, v); - - generateClassBody(aClass, v, kind); - - v.visitEnd(); + new ImplementationBodyCodegen(bindingContext, JetStandardLibrary.getJetStandardLibrary(project), aClass, kind, v).generate(); } - private String getSuperClass(JetClass aClass, OwnerKind kind) { - List delegationSpecifiers = aClass.getDelegationSpecifiers(); - - if (delegationSpecifiers.isEmpty()) return "java/lang/Object"; - - JetDelegationSpecifier first = delegationSpecifiers.get(0); - if (first instanceof JetDelegatorToSuperClass) { - JetType superType = bindingContext.resolveTypeReference(first.getTypeReference()); - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - PsiElement superPsi = bindingContext.getDeclarationPsiElement(superClassDescriptor); - if (superPsi instanceof PsiClass) { - PsiClass psiClass = (PsiClass) superPsi; - String fqn = psiClass.getQualifiedName(); - if (!psiClass.isInterface()) { - return fqn.replace('.', '/'); - } - } - } - else if (first instanceof JetDelegatorToSuperCall) { - JetType superType = bindingContext.resolveTypeReference(first.getTypeReference()); - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - return typeMapper.jvmName(superClassDescriptor, kind); - } - - return "java/lang/Object"; - } - - private Set getSuperInterfaces(JetClass aClass) { - List delegationSpecifiers = aClass.getDelegationSpecifiers(); - String superClassName = null; - Set superInterfaces = new LinkedHashSet(); - for (JetDelegationSpecifier specifier : delegationSpecifiers) { - JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference()); - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - PsiElement superPsi = bindingContext.getDeclarationPsiElement(superClassDescriptor); - - if (superPsi instanceof PsiClass) { - PsiClass psiClass = (PsiClass) superPsi; - String fqn = psiClass.getQualifiedName(); - if (psiClass.isInterface()) { - superInterfaces.add(fqn); - } - else { - if (superClassName == null) { - superClassName = fqn.replace('.', '/'); - - while (psiClass != null) { - for (PsiClass ifs : psiClass.getInterfaces()) { - superInterfaces.add(ifs.getQualifiedName().replace('.', '/')); - } - psiClass = psiClass.getSuperClass(); - } - } - else { - throw new RuntimeException("Cannot determine single class to inherit from"); - } - } - } - else { - superInterfaces.add(JetTypeMapper.jvmNameForInterface(superClassDescriptor)); - } - } - return superInterfaces; - } - - 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 - 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); - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, classDescriptor, kind); - - String classname = typeMapper.jvmName(classDescriptor, kind); - final Type classType = Type.getType("L" + classname + ";"); - - List specifiers = aClass.getDelegationSpecifiers(); - - if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) { - String superClass = getSuperClass(aClass, kind); - iv.load(0, Type.getType("L" + superClass + ";")); - iv.invokespecial(superClass, "", /* TODO super constructor descriptor */"()V"); - } - - int index = 0; - for (ClassDescriptor outerClassDescriptor : JetTypeMapper.getOuterClassDescriptors(classDescriptor)) { - final Type type = JetTypeMapper.jetInterfaceType(outerClassDescriptor); - String interfaceDesc = type.getDescriptor(); - final String fieldName = "this$" + index; - v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); - iv.load(0, classType); - iv.load(index + 1, type); - iv.putfield(classname, fieldName, interfaceDesc); - frameMap.enterTemp(); - } - - if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { - String interfaceDesc = JetTypeMapper.jetInterfaceType(classDescriptor).getDescriptor(); - v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "$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 firstTypeParameter = -1; - int typeParamCount = classDescriptor.getTypeConstructor().getParameters().size(); - if (kind == OwnerKind.IMPLEMENTATION) { - if (typeParamCount > 0) { - firstTypeParameter = frameMap.enterTemp(); - for (int i = 1; i < typeParamCount; i++) { - frameMap.enterTemp(); - } - } - } - - HashSet overriden = new HashSet(); - for (JetDeclaration declaration : aClass.getDeclarations()) { - if (declaration instanceof JetFunction) { - overriden.addAll(bindingContext.getFunctionDescriptor((JetFunction) declaration).getOverriddenFunctions()); - } - } - - - int n = 0; - for (JetDelegationSpecifier specifier : specifiers) { - boolean delegateOnStack = specifier instanceof JetDelegatorToSuperCall && n > 0 || - specifier instanceof JetDelegatorByExpressionSpecifier ; - - if (delegateOnStack) { - iv.load(0, classType); - } - - if (specifier instanceof JetDelegatorToSuperCall) { - JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier; - ConstructorDescriptor constructorDescriptor1 = bindingContext.resolveSuperConstructor(superCall, this); - - ClassDescriptor classDecl = constructorDescriptor1.getContainingDeclaration(); - boolean isDelegating = kind == OwnerKind.DELEGATING_IMPLEMENTATION; - Type type = isDelegating ? JetTypeMapper.jetDelegatingImplementationType(classDecl) : JetTypeMapper.jetImplementationType(classDecl); - - if (n > 0) { - if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { - codegen.thisToStack(); - } - } - - if (n == 0) { - iv.load(0, type); - } - else { - iv.anew(type); - iv.dup(); - } - - Method method1 = typeMapper.mapConstructorSignature(constructorDescriptor1, kind); - final Type[] argTypes1 = method1.getArgumentTypes(); - List args = superCall.getValueArguments(); - for (int i = 0, argsSize = args.size(); i < argsSize; i++) { - JetArgument arg = args.get(i); - codegen.gen(arg.getArgumentExpression(), argTypes1[i]); - } - - iv.invokespecial(type.getClassName(), "", method1.getDescriptor()); - } - else if (specifier instanceof JetDelegatorByExpressionSpecifier) { - codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression()); - } - - if (delegateOnStack) { - JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference()); - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - String delegateField = "$delegate_" + n; - Type fieldType = JetTypeMapper.jetInterfaceType(superClassDescriptor); - String fieldDesc = fieldType.getDescriptor(); - v.visitField(Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null); - iv.putfield(classname, delegateField, fieldDesc); - - JetClass superClass = (JetClass) bindingContext.getDeclarationPsiElement(superClassDescriptor); - generateDelegates(aClass, superClass, v, - new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), - JetTypeMapper.jvmNameForInterface(superClassDescriptor)), overriden); - } - - n++; - } - - if (firstTypeParameter > 0 && kind == OwnerKind.IMPLEMENTATION) { - generateTypeInfoInitializer(classDescriptor, firstTypeParameter, typeParamCount, iv); - } - - generateInitializers(aClass, kind, codegen, iv); - - int curParam = 0; - List constructorParameters = aClass.getPrimaryConstructorParameters(); - for (JetParameter parameter : constructorParameters) { - if (parameter.getValOrVarNode() != null) { - VariableDescriptor descriptor = paramDescrs.get(curParam); - Type type = typeMapper.mapType(descriptor.getOutType()); - iv.load(0, classType); - iv.load(frameMap.getIndex(descriptor), type); - iv.putfield(classname, descriptor.getName(), type.getDescriptor()); - } - curParam++; - } - - iv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } - - private void generateTypeInfoInitializer(ClassDescriptor classDescriptor, int firstTypeParameter, int typeParamCount, InstructionAdapter iv) { - iv.load(0, JetTypeMapper.TYPE_OBJECT); - iv.anew(JetTypeMapper.TYPE_TYPEINFO); - iv.dup(); - - iv.aconst(typeMapper.jvmType(classDescriptor, OwnerKind.INTERFACE)); - iv.iconst(typeParamCount); - iv.newarray(JetTypeMapper.TYPE_TYPEINFO); - - for (int i = 0; i < typeParamCount; i++) { - iv.dup(); - iv.iconst(i); - iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); - iv.astore(JetTypeMapper.TYPE_OBJECT); - } - iv.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;[Ljet/typeinfo/TypeInfo;)V"); - iv.putfield(typeMapper.jvmName(classDescriptor, OwnerKind.IMPLEMENTATION), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - } - - 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); - if (bindingContext.hasBackingField(propertyDescriptor)) { - final JetExpression initializer = ((JetProperty) declaration).getInitializer(); - if (initializer != null) { - iv.load(0, JetTypeMapper.TYPE_OBJECT); - codegen.genToJVMStack(initializer); - codegen.intermediateValueForProperty(propertyDescriptor, false).store(iv); - } - - } - } - } - } - - private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) { - final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - final FunctionCodegen functionCodegen = new FunctionCodegen(aClass, v, standardLibrary, bindingContext); - final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen); - - for (JetDeclaration declaration : aClass.getDeclarations()) { - if (declaration instanceof JetProperty) { - propertyCodegen.gen((JetProperty) declaration, kind); - } - else if (declaration instanceof JetFunction) { - try { - functionCodegen.gen((JetFunction) declaration, kind); - } catch (RuntimeException e) { - throw new RuntimeException("Error generating method "+ aClass.getName() + "." + declaration.getName(), e); - } - } - } - - for (JetParameter p : aClass.getPrimaryConstructorParameters()) { - if (p.getValOrVarNode() != null) { - PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p); - if (propertyDescriptor != null) { - propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); - if (propertyDescriptor.isVar()) { - propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); - } - - if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && bindingContext.hasBackingField(propertyDescriptor)) { - v.visitField(Opcodes.ACC_PRIVATE, p.getName(), typeMapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null); - } - } - } - } - } - - private void generateDelegates(JetClass inClass, JetClass toClass, ClassVisitor v, OwnerKind kind, Set overriden) { - final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, standardLibrary, bindingContext); - final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen); - - for (JetDeclaration declaration : toClass.getDeclarations()) { - if (declaration instanceof JetProperty) { - propertyCodegen.gen((JetProperty) declaration, kind); - } - else if (declaration instanceof JetFunction) { - if (!overriden.contains(bindingContext.getFunctionDescriptor((JetFunction) declaration))) { - functionCodegen.gen((JetFunction) declaration, kind); - } - } - } - - for (JetParameter p : toClass.getPrimaryConstructorParameters()) { - if (p.getValOrVarNode() != null) { - PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p); - if (propertyDescriptor != null) { - propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); - if (propertyDescriptor.isVar()) { - propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); - } - } - } - } - } - - private void generateStaticInitializer(ClassDescriptor descriptor, ClassVisitor cv) { - if (descriptor.getTypeConstructor().getParameters().size() > 0) { - // we will have a dynamic type info field - return; - } - final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, - "", "()V", null, null); - mv.visitCode(); - - InstructionAdapter v = new InstructionAdapter(mv); - newTypeInfo(v, Type.getObjectType(JetTypeMapper.jvmNameForInterface(descriptor))); - v.putstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - - mv.visitEnd(); - } public static void newTypeInfo(InstructionAdapter v, Type asmType) { v.anew(JetTypeMapper.TYPE_TYPEINFO); @@ -451,18 +58,4 @@ public class ClassCodegen { v.aconst(asmType); v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;)V"); } - - private void generateGetTypeInfo(ClassDescriptor descriptor, ClassVisitor cv) { - final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, - "getTypeInfo", - "()Ljet/typeinfo/TypeInfo;", - null /* TODO */, - null); - mv.visitCode(); - InstructionAdapter v = new InstructionAdapter(mv); - ExpressionCodegen.loadTypeInfo(descriptor, v); - v.areturn(JetTypeMapper.TYPE_TYPEINFO); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } } diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java new file mode 100644 index 00000000000..3069f4eb04a --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -0,0 +1,339 @@ +package org.jetbrains.jet.codegen; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +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.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author max + * @author yole + */ +public class ImplementationBodyCodegen extends ClassBodyCodegen { + public ImplementationBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClass aClass, OwnerKind kind, ClassVisitor v) { + super(bindingContext, stdlib, aClass, kind, v); + } + + @Override + protected void generateDeclaration() { + String superClass = getSuperClass(); + + final String defaultInterfaceName = JetTypeMapper.jvmNameForInterface(descriptor); + v.visit(Opcodes.V1_6, + Opcodes.ACC_PUBLIC, + JetTypeMapper.jetJvmName(descriptor, kind), + null, + superClass, + new String[]{"jet/JetObject", defaultInterfaceName} + ); + } + + private String getSuperClass() { + List delegationSpecifiers = myClass.getDelegationSpecifiers(); + + if (delegationSpecifiers.isEmpty()) return "java/lang/Object"; + + JetDelegationSpecifier first = delegationSpecifiers.get(0); + if (first instanceof JetDelegatorToSuperClass) { + JetType superType = bindingContext.resolveTypeReference(first.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + PsiElement superPsi = bindingContext.getDeclarationPsiElement(superClassDescriptor); + if (superPsi instanceof PsiClass) { + PsiClass psiClass = (PsiClass) superPsi; + String fqn = psiClass.getQualifiedName(); + if (!psiClass.isInterface()) { + return fqn.replace('.', '/'); + } + } + } + else if (first instanceof JetDelegatorToSuperCall) { + JetType superType = bindingContext.resolveTypeReference(first.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + return typeMapper.jvmName(superClassDescriptor, kind); + } + + return "java/lang/Object"; + } + + @Override + protected void generateSyntheticParts() { + int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC; + v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); + + generateStaticInitializer(); + + generatePrimaryConstructor(); + + generateGetTypeInfo(); + } + + private void generatePrimaryConstructor() { + ConstructorDescriptor constructorDescriptor = bindingContext.getConstructorDescriptor(myClass); + if (constructorDescriptor == null) return; + + Method method = typeMapper.mapConstructorSignature(constructorDescriptor, kind); + int flags = Opcodes.ACC_PUBLIC; // TODO + 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); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, descriptor, kind); + + String classname = typeMapper.jvmName(descriptor, kind); + final Type classType = Type.getType("L" + classname + ";"); + + List specifiers = myClass.getDelegationSpecifiers(); + + if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) { + String superClass = getSuperClass(); + iv.load(0, Type.getType("L" + superClass + ";")); + iv.invokespecial(superClass, "", /* TODO super constructor descriptor */"()V"); + } + + int index = 0; + for (ClassDescriptor outerClassDescriptor : JetTypeMapper.getOuterClassDescriptors(descriptor)) { + final Type type = JetTypeMapper.jetInterfaceType(outerClassDescriptor); + String interfaceDesc = type.getDescriptor(); + final String fieldName = "this$" + index; + v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); + iv.load(0, classType); + iv.load(index + 1, type); + iv.putfield(classname, fieldName, interfaceDesc); + frameMap.enterTemp(); + } + + if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { + String interfaceDesc = JetTypeMapper.jetInterfaceType(descriptor).getDescriptor(); + v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "$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 firstTypeParameter = -1; + int typeParamCount = descriptor.getTypeConstructor().getParameters().size(); + if (kind == OwnerKind.IMPLEMENTATION) { + if (typeParamCount > 0) { + firstTypeParameter = frameMap.enterTemp(); + for (int i = 1; i < typeParamCount; i++) { + frameMap.enterTemp(); + } + } + } + + HashSet overriden = new HashSet(); + for (JetDeclaration declaration : myClass.getDeclarations()) { + if (declaration instanceof JetFunction) { + overriden.addAll(bindingContext.getFunctionDescriptor((JetFunction) declaration).getOverriddenFunctions()); + } + } + + + int n = 0; + for (JetDelegationSpecifier specifier : specifiers) { + boolean delegateOnStack = specifier instanceof JetDelegatorToSuperCall && n > 0 || + specifier instanceof JetDelegatorByExpressionSpecifier ; + + if (delegateOnStack) { + iv.load(0, classType); + } + + if (specifier instanceof JetDelegatorToSuperCall) { + JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier; + ConstructorDescriptor constructorDescriptor1 = bindingContext.resolveSuperConstructor(superCall); + + ClassDescriptor classDecl = constructorDescriptor1.getContainingDeclaration(); + boolean isDelegating = kind == OwnerKind.DELEGATING_IMPLEMENTATION; + Type type = isDelegating ? JetTypeMapper.jetDelegatingImplementationType(classDecl) : JetTypeMapper.jetImplementationType(classDecl); + + if (n > 0) { + if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) { + codegen.thisToStack(); + } + } + + if (n == 0) { + iv.load(0, type); + } + else { + iv.anew(type); + iv.dup(); + } + + Method method1 = typeMapper.mapConstructorSignature(constructorDescriptor1, kind); + final Type[] argTypes1 = method1.getArgumentTypes(); + List args = superCall.getValueArguments(); + for (int i = 0, argsSize = args.size(); i < argsSize; i++) { + JetArgument arg = args.get(i); + codegen.gen(arg.getArgumentExpression(), argTypes1[i]); + } + + iv.invokespecial(type.getClassName(), "", method1.getDescriptor()); + } + else if (specifier instanceof JetDelegatorByExpressionSpecifier) { + codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression()); + } + + if (delegateOnStack) { + JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + String delegateField = "$delegate_" + n; + Type fieldType = JetTypeMapper.jetInterfaceType(superClassDescriptor); + String fieldDesc = fieldType.getDescriptor(); + v.visitField(Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null); + iv.putfield(classname, delegateField, fieldDesc); + + JetClass superClass = (JetClass) bindingContext.getDeclarationPsiElement(superClassDescriptor); + generateDelegates(myClass, superClass, + new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), + JetTypeMapper.jvmNameForInterface(superClassDescriptor)), overriden); + } + + n++; + } + + if (firstTypeParameter > 0 && kind == OwnerKind.IMPLEMENTATION) { + generateTypeInfoInitializer(firstTypeParameter, typeParamCount, iv); + } + + generateInitializers(codegen, iv); + + int curParam = 0; + List constructorParameters = myClass.getPrimaryConstructorParameters(); + for (JetParameter parameter : constructorParameters) { + if (parameter.getValOrVarNode() != null) { + VariableDescriptor descriptor = paramDescrs.get(curParam); + Type type = typeMapper.mapType(descriptor.getOutType()); + iv.load(0, classType); + iv.load(frameMap.getIndex(descriptor), type); + iv.putfield(classname, descriptor.getName(), type.getDescriptor()); + } + curParam++; + } + + iv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private void generateTypeInfoInitializer(int firstTypeParameter, int typeParamCount, InstructionAdapter iv) { + iv.load(0, JetTypeMapper.TYPE_OBJECT); + iv.anew(JetTypeMapper.TYPE_TYPEINFO); + iv.dup(); + + iv.aconst(typeMapper.jvmType(descriptor, OwnerKind.INTERFACE)); + iv.iconst(typeParamCount); + iv.newarray(JetTypeMapper.TYPE_TYPEINFO); + + for (int i = 0; i < typeParamCount; i++) { + iv.dup(); + iv.iconst(i); + iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); + iv.astore(JetTypeMapper.TYPE_OBJECT); + } + iv.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;[Ljet/typeinfo/TypeInfo;)V"); + iv.putfield(typeMapper.jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } + + private void generateInitializers(ExpressionCodegen codegen, InstructionAdapter iv) { + for (JetDeclaration declaration : myClass.getDeclarations()) { + if (declaration instanceof JetProperty) { + final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.getVariableDescriptor((JetProperty) declaration); + if (bindingContext.hasBackingField(propertyDescriptor)) { + final JetExpression initializer = ((JetProperty) declaration).getInitializer(); + if (initializer != null) { + iv.load(0, JetTypeMapper.TYPE_OBJECT); + codegen.genToJVMStack(initializer); + codegen.intermediateValueForProperty(propertyDescriptor, false).store(iv); + } + + } + } + } + } + + private void generateDelegates(JetClass inClass, JetClass toClass, OwnerKind kind, Set overriden) { + final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, stdlib, bindingContext); + final PropertyCodegen propertyCodegen = new PropertyCodegen(v, stdlib, bindingContext, functionCodegen); + + for (JetDeclaration declaration : toClass.getDeclarations()) { + if (declaration instanceof JetProperty) { + propertyCodegen.gen((JetProperty) declaration, kind); + } + else if (declaration instanceof JetFunction) { + if (!overriden.contains(bindingContext.getFunctionDescriptor((JetFunction) declaration))) { + functionCodegen.gen((JetFunction) declaration, kind); + } + } + } + + for (JetParameter p : toClass.getPrimaryConstructorParameters()) { + if (p.getValOrVarNode() != null) { + PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p); + if (propertyDescriptor != null) { + propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); + if (propertyDescriptor.isVar()) { + propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); + } + } + } + } + } + + private void generateStaticInitializer() { + if (descriptor.getTypeConstructor().getParameters().size() > 0) { + // we will have a dynamic type info field + return; + } + final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, + "", "()V", null, null); + mv.visitCode(); + + InstructionAdapter v = new InstructionAdapter(mv); + ClassCodegen.newTypeInfo(v, Type.getObjectType(JetTypeMapper.jvmNameForInterface(descriptor))); + v.putstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + + mv.visitEnd(); + } + + private void generateGetTypeInfo() { + final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, + "getTypeInfo", + "()Ljet/typeinfo/TypeInfo;", + null /* TODO */, + null); + mv.visitCode(); + InstructionAdapter v = new InstructionAdapter(mv); + ExpressionCodegen.loadTypeInfo(descriptor, v); + v.areturn(JetTypeMapper.TYPE_TYPEINFO); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java new file mode 100644 index 00000000000..d720062b7b4 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java @@ -0,0 +1,76 @@ +package org.jetbrains.jet.codegen; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetDelegationSpecifier; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * @author yole + */ +public class InterfaceBodyCodegen extends ClassBodyCodegen { + public InterfaceBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClass aClass, ClassVisitor v) { + super(bindingContext, stdlib, aClass, OwnerKind.INTERFACE, v); + } + + protected void generateDeclaration() { + Set superInterfaces = getSuperInterfaces(); + + String fqName = JetTypeMapper.jvmNameForInterface(descriptor); + v.visit(Opcodes.V1_6, + Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, + fqName, + null, + "java/lang/Object", + superInterfaces.toArray(new String[superInterfaces.size()]) + ); + } + + private Set getSuperInterfaces() { + List delegationSpecifiers = myClass.getDelegationSpecifiers(); + String superClassName = null; + Set superInterfaces = new LinkedHashSet(); + for (JetDelegationSpecifier specifier : delegationSpecifiers) { + JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference()); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + PsiElement superPsi = bindingContext.getDeclarationPsiElement(superClassDescriptor); + + if (superPsi instanceof PsiClass) { + PsiClass psiClass = (PsiClass) superPsi; + String fqn = psiClass.getQualifiedName(); + if (psiClass.isInterface()) { + superInterfaces.add(fqn); + } + else { + if (superClassName == null) { + superClassName = fqn.replace('.', '/'); + + while (psiClass != null) { + for (PsiClass ifs : psiClass.getInterfaces()) { + superInterfaces.add(ifs.getQualifiedName().replace('.', '/')); + } + psiClass = psiClass.getSuperClass(); + } + } + else { + throw new RuntimeException("Cannot determine single class to inherit from"); + } + } + } + else { + superInterfaces.add(JetTypeMapper.jvmNameForInterface(superClassDescriptor)); + } + } + return superInterfaces; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java index bcd56e1b67e..86d38107773 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -39,7 +39,7 @@ public interface BindingContext { boolean isStatement(JetExpression expression); boolean hasBackingField(PropertyDescriptor propertyDescriptor); - ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall, ClassCodegen classCodegen); + ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall); Collection getDiagnostics(); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index 6fd409578df..03c16b77261 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -7,12 +7,11 @@ import com.intellij.lang.ASTNode; 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.ErrorHandler; import org.jetbrains.jet.lang.JetDiagnostic; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.JetType; import java.util.*; @@ -266,7 +265,7 @@ public class BindingTraceContext implements BindingContext, BindingTrace { return backingFieldRequired.contains(propertyDescriptor); } - public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall, ClassCodegen classCodegen) { + public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall) { JetTypeReference typeReference = superCall.getTypeReference(); if (typeReference == null) return null; diff --git a/idea/tests/org/jetbrains/jet/JetTestUtils.java b/idea/tests/org/jetbrains/jet/JetTestUtils.java index bc6651ad18c..3d2033c6395 100644 --- a/idea/tests/org/jetbrains/jet/JetTestUtils.java +++ b/idea/tests/org/jetbrains/jet/JetTestUtils.java @@ -170,7 +170,7 @@ public class JetTestUtils { } @Override - public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall, ClassCodegen classCodegen) { + public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall) { throw new UnsupportedOperationException(); // TODO }