From be72e096ef8e5501afe99971bb2b7b6a14571463 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 21 May 2013 14:23:38 +0400 Subject: [PATCH] Realization of class object fields as static fields of outer class #KT-2213 Fixed --- .../AccessorForPropertyDescriptor.java | 8 +- .../org/jetbrains/jet/codegen/AsmUtil.java | 49 +++- .../jet/codegen/ClassBodyCodegen.java | 72 ++++-- .../jetbrains/jet/codegen/CodegenUtil.java | 19 +- .../jet/codegen/ExpressionCodegen.java | 62 +++-- .../codegen/FunctionGenerationStrategy.java | 2 +- .../codegen/ImplementationBodyCodegen.java | 211 ++++++++++++------ .../jetbrains/jet/codegen/MemberCodegen.java | 24 +- .../org/jetbrains/jet/codegen/MethodKind.java | 23 ++ .../jet/codegen/NamespaceCodegen.java | 6 +- .../jet/codegen/PropertyCodegen.java | 187 +++++++++------- .../jetbrains/jet/codegen/ScriptCodegen.java | 3 +- .../jet/codegen/TraitImplBodyCodegen.java | 6 +- .../context/AnonymousClassContext.java | 12 +- .../jet/codegen/context/CodegenContext.java | 13 +- .../jet/codegen/state/JetTypeMapper.java | 12 + .../jetbrains/jet/lang/psi/JetPsiUtil.java | 4 + .../jet/lang/resolve/DescriptorUtils.java | 14 ++ 18 files changed, 501 insertions(+), 226 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/MethodKind.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java index 97df1657f93..35a9193ff75 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java @@ -34,8 +34,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl { pd.isVar(), Name.identifier(pd.getName() + "$b$" + index), Kind.DECLARATION); - JetType receiverType = DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter()); - setType(pd.getType(), Collections.emptyList(), pd.getExpectedThisObject(), receiverType); + boolean isStaticProperty = AsmUtil.isPropertyWithBackingFieldInOuterClass(pd) + && !AsmUtil.isClassObjectWithBackingFieldsInOuter(containingDeclaration); + JetType receiverType = !isStaticProperty ? DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter()) : null; + + setType(pd.getType(), Collections.emptyList(), isStaticProperty ? null : pd.getExpectedThisObject(), + receiverType); initialize(new Getter(this), new Setter(this)); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index fbe222a069f..a2c63c40d4f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -30,7 +30,6 @@ import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; @@ -50,6 +49,7 @@ import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isKindOf; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; public class AsmUtil { @@ -589,10 +589,57 @@ public class AsmUtil { } } + public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { + return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS); + } + + public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) { + boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; + if (isDelegate || isExtensionProperty) { + return ACC_PRIVATE; + } else { + return areBothAccessorDefault(propertyDescriptor) ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE; + } + } + + private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) { + if (!propertyDescriptor.isVar() ) { + return propertyDescriptor; + } else { + return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor; + } + } + + public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) { + boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; + return !propertyDescriptor.isVar() && !isExtensionProperty + && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT) + && areBothAccessorDefault(propertyDescriptor) + && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC; + } + + public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) { + return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS); + } + + private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) { + return isAccessorWithEmptyBody(propertyDescriptor.getGetter()) + && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter())); + } + + private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) { + return accessorDescriptor == null || !accessorDescriptor.hasBody(); + } + + private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) { + return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind); + } + public static Type comparisonOperandType(Type left, Type right) { if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE; if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; return Type.INT_TYPE; } + } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index 8ef88ae3fdf..0a0fea7de56 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -17,9 +17,10 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; -import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.context.ClassContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; @@ -40,12 +41,20 @@ public abstract class ClassBodyCodegen extends MemberCodegen { protected final OwnerKind kind; protected final ClassDescriptor descriptor; protected final ClassBuilder v; - protected final CodegenContext context; + protected final ClassContext context; - protected final List staticInitializerChunks = new ArrayList(); + private MethodVisitor clInitMethod; - protected ClassBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) { - super(state); + private ExpressionCodegen clInitCodegen; + + protected ClassBodyCodegen( + @NotNull JetClassOrObject aClass, + @NotNull ClassContext context, + @NotNull ClassBuilder v, + @NotNull GenerationState state, + @Nullable MemberCodegen parentCodegen + ) { + super(state, parentCodegen); descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); myClass = aClass; this.context = context; @@ -53,7 +62,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen { this.v = v; } - public final void generate() { + public void generate() { generateDeclaration(); generateClassBody(); @@ -72,18 +81,20 @@ public abstract class ClassBodyCodegen extends MemberCodegen { private void generateClassBody() { FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state); - PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen); + PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this); - for (JetDeclaration declaration : myClass.getDeclarations()) { + if (kind != OwnerKind.TRAIT_IMPL) { //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts - if (shouldProcessFirst(declaration)) { - generateDeclaration(propertyCodegen, declaration, functionCodegen); + for (JetDeclaration declaration : myClass.getDeclarations()) { + if (shouldProcessFirst(declaration)) { + generateDeclaration(propertyCodegen, declaration); + } } } for (JetDeclaration declaration : myClass.getDeclarations()) { if (!shouldProcessFirst(declaration)) { - generateDeclaration(propertyCodegen, declaration, functionCodegen); + generateDeclaration(propertyCodegen, declaration); } } @@ -94,7 +105,8 @@ public abstract class ClassBodyCodegen extends MemberCodegen { return false == (declaration instanceof JetProperty || declaration instanceof JetNamedFunction); } - protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { + + protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) { if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) { genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v); } @@ -137,23 +149,39 @@ public abstract class ClassBodyCodegen extends MemberCodegen { } private void generateStaticInitializer() { - if (staticInitializerChunks.size() > 0) { - MethodVisitor mv = v.newMethod(null, ACC_STATIC, "", "()V", null, null); + if (clInitMethod != null) { + createOrGetClInitMethod(); + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { - mv.visitCode(); + ExpressionCodegen codegen = createOrGetClInitCodegen(); - ExpressionCodegen codegen = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context, state); - - for (CodeChunk chunk : staticInitializerChunks) { - chunk.generate(codegen); - } - - mv.visitInsn(RETURN); + createOrGetClInitMethod().visitInsn(RETURN); FunctionCodegen.endVisit(codegen.v, "static initializer", myClass); } } } + @Nullable + protected MethodVisitor createOrGetClInitMethod() { + if (clInitMethod == null) { + clInitMethod = v.newMethod(null, ACC_STATIC, "", "()V", null, null); + } + return clInitMethod; + } + + @Nullable + protected ExpressionCodegen createOrGetClInitCodegen() { + assert state.getClassBuilderMode() == ClassBuilderMode.FULL; + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + if (clInitCodegen == null) { + MethodVisitor method = createOrGetClInitMethod(); + method.visitCode(); + clInitCodegen = new ExpressionCodegen(method, new FrameMap(), Type.VOID_TYPE, context, state); + } + } + return clInitCodegen; + } + private void generateRemoveInIterator() { // generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index f0cfb552f19..57605e9648f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -27,6 +27,7 @@ import org.jetbrains.jet.codegen.context.NamespaceContext; import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; +import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; @@ -263,14 +264,26 @@ public class CodegenUtil { return false; } - public static boolean couldUseDirectAccessToProperty(PropertyDescriptor propertyDescriptor, boolean forGetter, boolean isInsideClass, boolean isDelegated) { + public static boolean couldUseDirectAccessToProperty(@NotNull PropertyDescriptor propertyDescriptor, boolean forGetter, boolean isInsideClass, boolean isDelegated) { PropertyAccessorDescriptor accessorDescriptor = forGetter ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; + boolean specialTypeProperty = isDelegated || + isExtensionProperty || + DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) || + JetTypeMapper.isAccessor(propertyDescriptor); return isInsideClass && - !isDelegated && - !isExtensionProperty && + !specialTypeProperty && (accessorDescriptor == null || accessorDescriptor.isDefault() && (!DescriptorUtils.isExternallyAccessible(propertyDescriptor) || accessorDescriptor.getModality() == Modality.FINAL)); } + + @NotNull + public static ImplementationBodyCodegen getParentBodyCodegen(@Nullable MemberCodegen classBodyCodegen) { + assert classBodyCodegen != null && + classBodyCodegen + .getParentCodegen() instanceof ImplementationBodyCodegen : "Class object should have appropriate parent BodyCodegen"; + + return ((ImplementationBodyCodegen) classBodyCodegen.getParentCodegen()); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 295167f4a53..0f69bb1dbbd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -87,6 +87,7 @@ public class ExpressionCodegen extends JetVisitor implem private int myLastLineNumber = -1; final InstructionAdapter v; + final MethodVisitor methodVisitor; final FrameMap myFrameMap; final JetTypeMapper typeMapper; @@ -121,8 +122,8 @@ public class ExpressionCodegen extends JetVisitor implem //noinspection SuspiciousMethodCalls CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); - CodegenContext objectContext = context.intoAnonymousClass(classDescriptor, this); - ImplementationBodyCodegen implementationBodyCodegen = new ImplementationBodyCodegen(objectDeclaration, objectContext, classBuilder, state); + ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this); + ImplementationBodyCodegen implementationBodyCodegen = new ImplementationBodyCodegen(objectDeclaration, objectContext, classBuilder, state, null); implementationBodyCodegen.generate(); @@ -164,7 +165,15 @@ public class ExpressionCodegen extends JetVisitor implem this.typeMapper = state.getTypeMapper(); this.returnType = returnType; this.state = state; - this.v = new InstructionAdapter(v) { + this.methodVisitor = v; + this.v = createInstructionAdapter(methodVisitor); + this.bindingContext = state.getBindingContext(); + this.context = context; + this.statementVisitor = new CodegenStatementVisitor(this); + } + + protected InstructionAdapter createInstructionAdapter(MethodVisitor mv) { + return new InstructionAdapter(methodVisitor) { @Override public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { super.visitLocalVariable(name, desc, signature, start, end, @@ -172,9 +181,6 @@ public class ExpressionCodegen extends JetVisitor implem localVariableNames.add(name); } }; - this.bindingContext = state.getBindingContext(); - this.context = context; - this.statementVisitor = new CodegenStatementVisitor(this); } public GenerationState getState() { @@ -275,9 +281,9 @@ public class ExpressionCodegen extends JetVisitor implem ClassBuilder classBuilder = state.getFactory().newVisitor(className.getInternalName(), declaration.getContainingFile() ); - CodegenContext objectContext = context.intoAnonymousClass(descriptor, this); + ClassContext objectContext = context.intoAnonymousClass(descriptor, this); - new ImplementationBodyCodegen(declaration, objectContext, classBuilder, state).generate(); + new ImplementationBodyCodegen(declaration, objectContext, classBuilder, state, null).generate(); return StackValue.none(); } @@ -1673,26 +1679,26 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull public StackValue.Property intermediateValueForProperty( - PropertyDescriptor propertyDescriptor, + @NotNull PropertyDescriptor propertyDescriptor, boolean forceField, @Nullable JetSuperExpression superExpression ) { - return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false); + return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL); } - @NotNull public StackValue.Property intermediateValueForProperty( - PropertyDescriptor propertyDescriptor, + @NotNull PropertyDescriptor propertyDescriptor, boolean forceField, @Nullable JetSuperExpression superExpression, - @NotNull boolean forceSpecialFlag + @NotNull MethodKind methodKind ) { JetTypeMapper typeMapper = state.getTypeMapper(); DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); assert containingDeclaration != null; - boolean isStatic = containingDeclaration instanceof NamespaceDescriptor; + boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor); + boolean isStatic = containingDeclaration instanceof NamespaceDescriptor || isBackingFieldInAnotherClass; boolean isSuper = superExpression != null; boolean isInsideClass = isCallInsideSameClassAsDeclared(propertyDescriptor, context); boolean isInsideModule = isCallInsideSameModuleAsDeclared(propertyDescriptor, context); @@ -1700,10 +1706,25 @@ public class ExpressionCodegen extends JetVisitor implem JetType delegateType = getPropertyDelegateType(propertyDescriptor, state.getBindingContext()); boolean isDelegatedProperty = delegateType != null; + CallableMethod callableGetter = null; CallableMethod callableSetter = null; - if (!forceField) { + boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass; + + CodegenContext backingFieldContext = context.getParentContext(); + + if (isBackingFieldInAnotherClass && forceField) { + //delegate call to classObject owner : OWNER + backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration()); + int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty); + skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER; + if (!skipPropertyAccessors) { + propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor); + } + } + + if (!skipPropertyAccessors) { //noinspection ConstantConditions if (couldUseDirectAccessToProperty(propertyDescriptor, true, isInsideClass, isDelegatedProperty)) { callableGetter = null; @@ -1721,7 +1742,9 @@ public class ExpressionCodegen extends JetVisitor implem propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor); if (propertyDescriptor.getGetter() != null) { - callableGetter = typeMapper.mapToCallableMethod(propertyDescriptor.getGetter(), isSuper || forceSpecialFlag, isInsideClass, isInsideModule, OwnerKind.IMPLEMENTATION); + callableGetter = typeMapper + .mapToCallableMethod(propertyDescriptor.getGetter(), isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, + isInsideClass, isInsideModule, OwnerKind.IMPLEMENTATION); } } @@ -1731,7 +1754,7 @@ public class ExpressionCodegen extends JetVisitor implem callableSetter = null; } else { - callableSetter = typeMapper.mapToCallableMethod(propertyDescriptor.getSetter(), isSuper || forceSpecialFlag, isInsideClass, isInsideModule, OwnerKind.IMPLEMENTATION); + callableSetter = typeMapper.mapToCallableMethod(propertyDescriptor.getSetter(), isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, isInsideClass, isInsideModule, OwnerKind.IMPLEMENTATION); } } } @@ -1742,7 +1765,7 @@ public class ExpressionCodegen extends JetVisitor implem propertyDescriptor = unwrapFakeOverride(propertyDescriptor); if (callableMethod == null) { - owner = typeMapper.getOwner(propertyDescriptor, context.getContextKind(), isInsideModule); + owner = typeMapper.getOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, context.getContextKind(), isInsideModule); } else { owner = callableMethod.getOwner(); @@ -2316,8 +2339,7 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull public Type expressionType(JetExpression expr) { - JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr); - return asmTypeOrVoid(type); + return typeMapper.expressionType(expr); } public int indexOfLocal(JetReferenceExpression lhs) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java index 6a7f7426e47..204786833c4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java @@ -85,7 +85,7 @@ public abstract class FunctionGenerationStrategy { public abstract static class CodegenBased extends FunctionGenerationStrategy { - private final GenerationState state; + protected final GenerationState state; protected final T callableDescriptor; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 05668955841..d32993d3d71 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -31,7 +31,7 @@ import org.jetbrains.asm4.commons.Method; import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.binding.CodegenBinding; import org.jetbrains.jet.codegen.binding.MutableClosure; -import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.context.ClassContext; import org.jetbrains.jet.codegen.context.ConstructorContext; import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.signature.*; @@ -67,6 +67,7 @@ import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isKindOf; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; @@ -79,13 +80,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private final Type classAsmType; private final FunctionCodegen functionCodegen; - private final PropertyCodegen propertyCodegen; + private final PropertyCodegen propertyCodegen; - public ImplementationBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) { - super(aClass, context, v, state); + private List classObjectPropertiesToCopy; + + public ImplementationBodyCodegen( + @NotNull JetClassOrObject aClass, + @NotNull ClassContext context, + @NotNull ClassBuilder v, + @NotNull GenerationState state, + @Nullable MemberCodegen parentCodegen + ) { + super(aClass, context, v, state, parentCodegen); this.classAsmType = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL); this.functionCodegen = new FunctionCodegen(context, v, state); - this.propertyCodegen = new PropertyCodegen(context, v, this.functionCodegen); + this.propertyCodegen = new PropertyCodegen(context, v, this.functionCodegen, this); } @Override @@ -429,6 +438,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void generateSyntheticParts() { generateFieldForSingleton(); + generateClassObjectBackingFieldCopies(); + try { generatePrimaryConstructor(); } @@ -446,7 +457,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateSyntheticAccessors(); - generateEnumMethods(); + generateEnumMethodsAndConstInitializers(); generateFunctionsForDataClasses(); @@ -750,25 +761,33 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { MethodContext functionContext = context.intoFunction(function); FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION, - new DefaultParameterValueLoader() { - @Override - public void putValueOnStack( - ValueParameterDescriptor descriptor, - ExpressionCodegen codegen - ) { - assert (KotlinBuiltIns.getInstance() - .isData((ClassDescriptor) function.getContainingDeclaration())) - : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation"; - PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get( - BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor); - assert propertyDescriptor != - null : "Trying to generate default value for parameter of copy function that doesn't correspond to any property"; - codegen.v.load(0, thisDescriptorType); - Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType()); - codegen.intermediateValueForProperty(propertyDescriptor, false, null) - .put(propertyType, codegen.v); - } - }); + new DefaultParameterValueLoader() { + @Override + public void putValueOnStack( + ValueParameterDescriptor descriptor, + ExpressionCodegen codegen + ) { + assert (KotlinBuiltIns.getInstance().isData((ClassDescriptor) function.getContainingDeclaration())) + : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation"; + PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get( + BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor); + assert propertyDescriptor != null + : "Trying to generate default value for parameter of copy function that doesn't correspond to any property"; + codegen.v.load(0, thisDescriptorType); + Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType()); + codegen.intermediateValueForProperty(propertyDescriptor, false, null).put(propertyType, codegen.v); + } + }); +} + + private void generateEnumMethodsAndConstInitializers() { + if (!myEnumConstants.isEmpty()) { + generateEnumMethods(); + + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + initializeEnumConstants(createOrGetClInitCodegen()); + } + } } private void generateEnumMethods() { @@ -827,7 +846,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { }); } else if (entry.getValue() instanceof PropertyDescriptor) { - PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue(); + final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue(); final PropertyDescriptor original = (PropertyDescriptor) entry.getKey(); @@ -837,9 +856,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { new FunctionGenerationStrategy.CodegenBased(state, getter) { @Override public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { - StackValue.Property property = codegen.intermediateValueForProperty(original, false, null, true); InstructionAdapter iv = codegen.v; - iv.load(0, OBJECT_TYPE); + boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && !isClassObject(bridge.getContainingDeclaration()); + StackValue.Property property = codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR); + if (!forceField) { + iv.load(0, OBJECT_TYPE); + } property.put(property.type, iv); iv.areturn(signature.getAsmMethod().getReturnType()); } @@ -854,12 +876,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { new FunctionGenerationStrategy.CodegenBased(state, setter) { @Override public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { - StackValue.Property property = codegen.intermediateValueForProperty(original, false, null, true); + boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && !isClassObject(bridge.getContainingDeclaration()); + StackValue.Property property = codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR); InstructionAdapter iv = codegen.v; - iv.load(0, OBJECT_TYPE); Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); - for (int i = 1, reg = 1; i < argTypes.length; i++) { + for (int i = 0, reg = 0; i < argTypes.length; i++) { Type argType = argTypes[i]; iv.load(reg, argType); //noinspection AssignmentToForLoopParameter @@ -915,22 +937,64 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (!(isNonLiteralObject(myClass) || hasClassObject) || isEnumClass) return; - final ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor; + ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor; assert fieldTypeDescriptor != null; - final StackValue.Field field = StackValue.singleton(fieldTypeDescriptor, typeMapper); + StackValue.Field field = StackValue.singleton(fieldTypeDescriptor, typeMapper); JetClassOrObject original = hasClassObject ? ((JetClass) myClass).getClassObject().getObjectDeclaration() : myClass; v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null); - staticInitializerChunks.add(new CodeChunk() { - @Override - public void generate(ExpressionCodegen codegen) { - ConstructorDescriptor constructorDescriptor = DescriptorUtils.getConstructorOfSingletonObject(fieldTypeDescriptor); - FunctionDescriptor fd = codegen.accessableFunctionDescriptor(constructorDescriptor); - generateMethodCallTo(fd, codegen.v); - field.store(field.type, codegen.v); + if (!AsmUtil.isClassObjectWithBackingFieldsInOuter(fieldTypeDescriptor)) { + genInitSingleton(fieldTypeDescriptor, field); + } + } + + private void generateClassObjectBackingFieldCopies() { + if (classObjectPropertiesToCopy != null) { + for (PropertyDescriptor propertyDescriptor : classObjectPropertiesToCopy) { + + v.newField(null, ACC_STATIC | ACC_FINAL | ACC_PUBLIC, propertyDescriptor.getName().asString(), typeMapper.mapType(propertyDescriptor).getDescriptor(), null, null); + + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + ExpressionCodegen codegen = createOrGetClInitCodegen(); + int classObjectIndex = putClassObjectInLocalVar(codegen); + StackValue.local(classObjectIndex, OBJECT_TYPE).put(OBJECT_TYPE, codegen.v); + copyFieldFromClassObject(propertyDescriptor); + } } - }); + } + } + + private int putClassObjectInLocalVar(ExpressionCodegen codegen) { + FrameMap frameMap = codegen.myFrameMap; + ClassDescriptor classObjectDescriptor = descriptor.getClassObjectDescriptor(); + int classObjectIndex = frameMap.getIndex(classObjectDescriptor); + if (classObjectIndex == -1) { + classObjectIndex = frameMap.enter(classObjectDescriptor, OBJECT_TYPE); + StackValue classObject = StackValue.singleton(classObjectDescriptor, typeMapper); + classObject.put(classObject.type, codegen.v); + StackValue.local(classObjectIndex, classObject.type).store(classObject.type, codegen.v); + } + return classObjectIndex; + } + + private void copyFieldFromClassObject(PropertyDescriptor propertyDescriptor) { + ExpressionCodegen codegen = createOrGetClInitCodegen(); + StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null); + property.put(property.type, codegen.v); + StackValue.Field field = StackValue.field(property.type, JvmClassName.byClassDescriptor(descriptor), + propertyDescriptor.getName().asString(), true); + field.store(field.type, codegen.v); + } + + protected void genInitSingleton(ClassDescriptor fieldTypeDescriptor, StackValue.Field field) { + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + ConstructorDescriptor constructorDescriptor = DescriptorUtils.getConstructorOfSingletonObject(fieldTypeDescriptor); + ExpressionCodegen codegen = createOrGetClInitCodegen(); + FunctionDescriptor fd = codegen.accessableFunctionDescriptor(constructorDescriptor); + generateMethodCallTo(fd, codegen.v); + field.store(field.type, codegen.v); + } } protected void generatePrimaryConstructor() { @@ -981,9 +1045,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generatePrimaryConstructorImpl( - ConstructorDescriptor constructorDescriptor, - ExpressionCodegen codegen, - MutableClosure closure + @Nullable ConstructorDescriptor constructorDescriptor, + @NotNull final ExpressionCodegen codegen, + @Nullable MutableClosure closure ) { List paramDescrs = constructorDescriptor != null ? constructorDescriptor.getValueParameters() @@ -1035,7 +1099,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { curParam++; } - generateInitializers(codegen, iv, myClass.getDeclarations(), bindingContext, state); + boolean generateInitializerInOuter = isClassObjectWithBackingFieldsInOuter(descriptor); + if (generateInitializerInOuter) { + ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this); + //generate object$ + parentCodegen.genInitSingleton(descriptor, StackValue.singleton(descriptor, typeMapper)); + parentCodegen.generateInitializers(parentCodegen.createOrGetClInitCodegen(), + myClass.getDeclarations(), bindingContext, state); + } else { + generateInitializers(codegen, myClass.getDeclarations(), bindingContext, state); + } + iv.visitInsn(RETURN); } @@ -1225,7 +1299,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generateTraitMethods() { - if (myClass instanceof JetClass && ((JetClass) myClass).isTrait()) { + if (JetPsiUtil.isTrait(myClass)) { return; } @@ -1425,29 +1499,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } @Override - protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { + protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) { if (declaration instanceof JetEnumEntry) { String name = declaration.getName(); String desc = "L" + classAsmType.getInternalName() + ";"; v.newField(declaration, ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null); - if (myEnumConstants.isEmpty()) { - staticInitializerChunks.add(new CodeChunk() { - @Override - public void generate(ExpressionCodegen codegen) { - initializeEnumConstants(codegen.v); - } - }); - } myEnumConstants.add((JetEnumEntry) declaration); } - super.generateDeclaration(propertyCodegen, declaration, functionCodegen); + super.generateDeclaration(propertyCodegen, declaration); } private final List myEnumConstants = new ArrayList(); - private void initializeEnumConstants(InstructionAdapter iv) { - ExpressionCodegen codegen = new ExpressionCodegen(iv, new FrameMap(), Type.VOID_TYPE, context, state); + private void initializeEnumConstants(ExpressionCodegen codegen) { + InstructionAdapter iv = codegen.v; int ordinal = -1; JetType myType = descriptor.getDefaultType(); Type myAsmType = typeMapper.mapType(myType, JetTypeMapperMode.IMPL); @@ -1509,14 +1575,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } public static void generateInitializers( - @NotNull ExpressionCodegen codegen, @NotNull InstructionAdapter iv, @NotNull List declarations, + @NotNull ExpressionCodegen codegen, @NotNull List declarations, @NotNull BindingContext bindingContext, @NotNull GenerationState state ) { JetTypeMapper typeMapper = state.getTypeMapper(); for (JetDeclaration declaration : declarations) { if (declaration instanceof JetProperty) { if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) { - initializeProperty(codegen, bindingContext, iv, (JetProperty) declaration, false); + initializeProperty(codegen, bindingContext, (JetProperty) declaration); } } else if (declaration instanceof JetClassInitializer) { @@ -1525,16 +1591,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + public static void initializeProperty( @NotNull ExpressionCodegen codegen, @NotNull BindingContext bindingContext, - @NotNull InstructionAdapter iv, - @NotNull JetProperty property, - boolean isStatic + @NotNull JetProperty property ) { - if (!isStatic) { - iv.load(0, OBJECT_TYPE); - } PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property); assert propertyDescriptor != null; @@ -1543,14 +1605,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; JetType jetType = getPropertyOrDelegateType(bindingContext, property, propertyDescriptor); + + StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER); + + if (!propValue.isStatic) { + codegen.v.load(0, OBJECT_TYPE); + } + Type type = codegen.expressionType(initializer); if (jetType.isNullable()) { type = boxType(type); } codegen.gen(initializer, type); - StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null); - propValue.store(type, iv); + propValue.store(type, codegen.v); } public static boolean shouldInitializeProperty( @@ -1699,4 +1767,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return r; } + public void addClassObjectPropertyToCopy(PropertyDescriptor descriptor) { + if (classObjectPropertiesToCopy == null) { + classObjectPropertiesToCopy = new ArrayList(); + } + classObjectPropertiesToCopy.add(descriptor); + } + } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index 89627161c90..41ecee8aaed 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -17,22 +17,32 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.context.ClassContext; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationStateAware; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.ErrorUtils; -import java.util.Map; +import java.util.List; -import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass; public class MemberCodegen extends GenerationStateAware { - public MemberCodegen(@NotNull GenerationState state) { + + @Nullable + private MemberCodegen parentCodegen; + + public MemberCodegen(@NotNull GenerationState state, @Nullable MemberCodegen parentCodegen) { super(state); + this.parentCodegen = parentCodegen; + } + + @Nullable + public MemberCodegen getParentCodegen() { + return parentCodegen; } public void genFunctionOrProperty( @@ -54,7 +64,7 @@ public class MemberCodegen extends GenerationStateAware { } else if (functionOrProperty instanceof JetProperty) { try { - new PropertyCodegen(context, classBuilder, functionCodegen).gen((JetProperty) functionOrProperty); + new PropertyCodegen(context, classBuilder, functionCodegen, this).gen((JetProperty) functionOrProperty); } catch (CompilationException e) { throw e; @@ -80,8 +90,8 @@ public class MemberCodegen extends GenerationStateAware { } ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile()); - CodegenContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state); - new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate(); + ClassContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state); + new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, this).generate(); classBuilder.done(); if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MethodKind.java b/compiler/backend/src/org/jetbrains/jet/codegen/MethodKind.java new file mode 100644 index 00000000000..e0d1634880a --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MethodKind.java @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen; + +public enum MethodKind { + GENERAL, + INITIALIZER, + SYNTHETIC_ACCESSOR +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 7c3e2e34336..08f7f5a6a92 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -26,11 +26,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; -import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -56,7 +54,7 @@ public class NamespaceCodegen extends MemberCodegen { GenerationState state, Collection namespaceFiles ) { - super(state); + super(state, null); checkAllFilesHaveSameNamespace(namespaceFiles); this.v = v; @@ -218,7 +216,7 @@ public class NamespaceCodegen extends MemberCodegen { for (JetDeclaration declaration : properties) { ImplementationBodyCodegen. - initializeProperty(codegen, state.getBindingContext(), new InstructionAdapter(mv), (JetProperty) declaration, true); + initializeProperty(codegen, state.getBindingContext(), (JetProperty) declaration); } mv.visitInsn(RETURN); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 493de79443b..46b6820effd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -19,24 +19,29 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.FieldVisitor; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.context.ClassContext; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; +import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationStateAware; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorResolver; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; import org.jetbrains.jet.lang.resolve.name.Name; @@ -46,31 +51,44 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.AsmUtil.getDeprecatedAccessFlag; +import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityForSpecialPropertyBackingField; import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; public class PropertyCodegen extends GenerationStateAware { + @NotNull private final FunctionCodegen functionCodegen; + + @NotNull private final ClassBuilder v; + + @NotNull private final CodegenContext context; + + @Nullable + private MemberCodegen classBodyCodegen; + + @NotNull private final OwnerKind kind; - public PropertyCodegen(CodegenContext context, ClassBuilder v, FunctionCodegen functionCodegen) { + public PropertyCodegen( + @NotNull CodegenContext context, + @NotNull ClassBuilder v, + @NotNull FunctionCodegen functionCodegen, + @Nullable MemberCodegen classBodyCodegen + ) { super(functionCodegen.getState()); this.v = v; this.functionCodegen = functionCodegen; this.context = context; + this.classBodyCodegen = classBodyCodegen; this.kind = context.getContextKind(); } public void gen(JetProperty p) { - VariableDescriptor descriptor = bindingContext.get(BindingContext.VARIABLE, p); - if (!(descriptor instanceof PropertyDescriptor)) { - throw new UnsupportedOperationException("expect a property to have a property descriptor"); - } - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + PropertyDescriptor propertyDescriptor = DescriptorUtils.getPropertyDescriptor(p, bindingContext); assert kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL - : "Generating property with a wrong kind (" + kind + "): " + descriptor; + : "Generating property with a wrong kind (" + kind + "): " + propertyDescriptor; if (kind != OwnerKind.TRAIT_IMPL && !(kind instanceof OwnerKind.StaticDelegateKind)) { generateBackingField(p, propertyDescriptor); @@ -89,7 +107,7 @@ public class PropertyCodegen extends GenerationStateAware { } } - private void generateBackingField(PsiElement p, PropertyDescriptor propertyDescriptor) { + private void generateBackingField(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { //noinspection ConstantConditions boolean hasBackingField = bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); boolean isDelegated = p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null; @@ -108,25 +126,56 @@ public class PropertyCodegen extends GenerationStateAware { } - private FieldVisitor generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) { - int modifiers = ACC_PRIVATE | ACC_FINAL | getDeprecatedAccessFlag(propertyDescriptor); - if (kind == OwnerKind.NAMESPACE) { - modifiers |= ACC_STATIC; - } + private FieldVisitor generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) { + int modifiers = getDeprecatedAccessFlag(propertyDescriptor); + if (KotlinBuiltIns.getInstance().isVolatile(propertyDescriptor)) { modifiers |= ACC_VOLATILE; } + + if (kind == OwnerKind.NAMESPACE) { + modifiers |= ACC_STATIC; + } + + if (!propertyDescriptor.isVar() || isDelegate) { + modifiers |= ACC_FINAL; + } + + Type type = typeMapper.mapType(jetType); + + ClassBuilder builder = v; + + if (AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) { + modifiers |= ACC_STATIC | getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate); + builder = getParentBodyCodegen(classBodyCodegen).v; + } else { + if (kind != OwnerKind.NAMESPACE || isDelegate) { + modifiers |= ACC_PRIVATE; + } + } + + if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) { + ImplementationBodyCodegen parentBodyCodegen = getParentBodyCodegen(classBodyCodegen); + parentBodyCodegen.addClassObjectPropertyToCopy(propertyDescriptor); + } + + String name = isDelegate ? JvmAbi.getPropertyDelegateName(propertyDescriptor.getName()) : propertyDescriptor.getName().asString(); + + return builder.newField(element, modifiers, name, type.getDescriptor(), + null, defaultValue); + } + + private FieldVisitor generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) { JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, p.getDelegateExpression()); if (delegateType == null) { // If delegate expression is unresolved reference delegateType = ErrorUtils.createErrorType("Delegate type"); } - Type type = typeMapper.mapType(delegateType); - return v.newField(p, modifiers, JvmAbi.getPropertyDelegateName(propertyDescriptor.getName()), type.getDescriptor(), - null, null); + + return generateBackingField(p, propertyDescriptor, true, delegateType, null); } - private FieldVisitor generateBackingFieldAccess(PsiElement p, PropertyDescriptor propertyDescriptor) { + private FieldVisitor generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { Object value = null; if (p instanceof JetProperty && !ImplementationBodyCodegen.shouldInitializeProperty((JetProperty) p, typeMapper)) { JetExpression initializer = ((JetProperty) p).getInitializer(); @@ -135,22 +184,8 @@ public class PropertyCodegen extends GenerationStateAware { value = compileTimeValue != null ? compileTimeValue.getValue() : null; } } - int modifiers; - if (kind == OwnerKind.NAMESPACE) { - modifiers = ACC_STATIC; - } - else { - modifiers = ACC_PRIVATE; - } - if (!propertyDescriptor.isVar()) { - modifiers |= ACC_FINAL; - } - modifiers |= getDeprecatedAccessFlag(propertyDescriptor); - if (KotlinBuiltIns.getInstance().isVolatile(propertyDescriptor)) { - modifiers |= ACC_VOLATILE; - } - Type type = typeMapper.mapType(propertyDescriptor); - return v.newField(p, modifiers, propertyDescriptor.getName().asString(), type.getDescriptor(), null, value); + + return generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value); } private void generateGetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor getter) { @@ -166,10 +201,10 @@ public class PropertyCodegen extends GenerationStateAware { FunctionGenerationStrategy strategy; if (defaultGetter) { if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) { - strategy = new DefaultPropertyWithDelegateAccessorStrategy(getterDescriptor); + strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, getterDescriptor); } else { - strategy = new DefaultPropertyAccessorStrategy(getterDescriptor); + strategy = new DefaultPropertyAccessorStrategy(state, getterDescriptor); } } else { @@ -197,10 +232,10 @@ public class PropertyCodegen extends GenerationStateAware { FunctionGenerationStrategy strategy; if (defaultSetter) { if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) { - strategy = new DefaultPropertyWithDelegateAccessorStrategy(setterDescriptor); + strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, setterDescriptor); } else { - strategy = new DefaultPropertyAccessorStrategy(setterDescriptor); + strategy = new DefaultPropertyAccessorStrategy(state, setterDescriptor); } } else { @@ -216,90 +251,82 @@ public class PropertyCodegen extends GenerationStateAware { } - private class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy { - private final PropertyAccessorDescriptor descriptor; + private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { - public DefaultPropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor descriptor) { - this.descriptor = descriptor; + public DefaultPropertyAccessorStrategy( + @NotNull GenerationState state, + @NotNull PropertyAccessorDescriptor callableDescriptor + ) { + super(state, callableDescriptor); } @Override - public void generateBody( - @NotNull MethodVisitor mv, - @NotNull JvmMethodSignature signature, - @NotNull MethodContext context + public void doGenerateBody( + ExpressionCodegen codegen, JvmMethodSignature signature ) { - generateDefaultAccessor(descriptor, new InstructionAdapter(mv), typeMapper, context); + generateDefaultAccessor(callableDescriptor, codegen.v, codegen); } } private static void generateDefaultAccessor( @NotNull PropertyAccessorDescriptor accessorDescriptor, @NotNull InstructionAdapter iv, - @NotNull JetTypeMapper typeMapper, - @NotNull CodegenContext context + @NotNull ExpressionCodegen codegen ) { + JetTypeMapper typeMapper = codegen.typeMapper; + CodegenContext context = codegen.context; OwnerKind kind = context.getContextKind(); PropertyDescriptor propertyDescriptor = accessorDescriptor.getCorrespondingProperty(); Type type = typeMapper.mapType(propertyDescriptor); + + int paramCode = 0; + if (kind != OwnerKind.NAMESPACE) { + iv.load(0, OBJECT_TYPE); + paramCode = 1; + } + + StackValue property = codegen.intermediateValueForProperty(accessorDescriptor.getCorrespondingProperty(), true, null); + if (accessorDescriptor instanceof PropertyGetterDescriptor) { - if (kind != OwnerKind.NAMESPACE) { - iv.load(0, OBJECT_TYPE); - } - iv.visitFieldInsn( - kind == OwnerKind.NAMESPACE ? GETSTATIC : GETFIELD, - typeMapper.getOwner(propertyDescriptor, kind, isCallInsideSameModuleAsDeclared(propertyDescriptor, context)).getInternalName(), - propertyDescriptor.getName().asString(), - type.getDescriptor()); + property.put(type, iv); iv.areturn(type); } else if (accessorDescriptor instanceof PropertySetterDescriptor) { - int paramCode = 0; - if (kind != OwnerKind.NAMESPACE) { - iv.load(0, OBJECT_TYPE); - paramCode = 1; - } ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter(); if (receiverParameter != null) { paramCode += typeMapper.mapType(receiverParameter.getType()).getSize(); } iv.load(paramCode, type); - iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? PUTSTATIC : PUTFIELD, - typeMapper.getOwner(propertyDescriptor, kind, isCallInsideSameModuleAsDeclared(propertyDescriptor, context)).getInternalName(), - propertyDescriptor.getName().asString(), - type.getDescriptor()); + property.store(type, iv); iv.visitInsn(RETURN); } else { assert false : "Unreachable state"; } } - private class DefaultPropertyWithDelegateAccessorStrategy extends FunctionGenerationStrategy { - private final PropertyAccessorDescriptor descriptor; - - public DefaultPropertyWithDelegateAccessorStrategy(@NotNull PropertyAccessorDescriptor descriptor) { - this.descriptor = descriptor; + private static class DefaultPropertyWithDelegateAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { + public DefaultPropertyWithDelegateAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) { + super(state, descriptor); } @Override - public void generateBody( - @NotNull MethodVisitor mv, - @NotNull JvmMethodSignature signature, - @NotNull MethodContext context + public void doGenerateBody( + @NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature ) { - InstructionAdapter iv = new InstructionAdapter(mv); - ExpressionCodegen codegen = new ExpressionCodegen( - mv, getFrameMap(typeMapper, context), signature.getAsmMethod().getReturnType(), context, state); + JetTypeMapper typeMapper = codegen.typeMapper; + OwnerKind kind = codegen.context.getContextKind(); + InstructionAdapter iv = codegen.v; + BindingContext bindingContext = state.getBindingContext(); ResolvedCall resolvedCall = - bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, descriptor); + bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor); - Call call = bindingContext.get(BindingContext.DELEGATED_PROPERTY_CALL, descriptor); + Call call = bindingContext.get(BindingContext.DELEGATED_PROPERTY_CALL, callableDescriptor); assert call != null : "Call should be recorded for delegate call " + signature.toString(); - PropertyDescriptor property = descriptor.getCorrespondingProperty(); + PropertyDescriptor property = callableDescriptor.getCorrespondingProperty(); Type asmType = typeMapper.mapType(property); if (kind != OwnerKind.NAMESPACE) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java index 5861fa2a645..e7323990991 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java @@ -53,7 +53,7 @@ public class ScriptCodegen extends MemberCodegen { private Method scriptConstructorMethod; public ScriptCodegen(@NotNull GenerationState state) { - super(state); + super(state, null); } @Inject @@ -145,7 +145,6 @@ public class ScriptCodegen extends MemberCodegen { ImplementationBodyCodegen.generateInitializers( new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state), - instructionAdapter, scriptDeclaration.getDeclarations(), bindingContext, state); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 47042069858..1f04bcc9c5d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -16,7 +16,7 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.context.ClassContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapperMode; import org.jetbrains.jet.lang.psi.JetClassOrObject; @@ -24,8 +24,8 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject; import static org.jetbrains.asm4.Opcodes.*; public class TraitImplBodyCodegen extends ClassBodyCodegen { - public TraitImplBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) { - super(aClass, context, v, state); + public TraitImplBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassBuilder v, GenerationState state) { + super(aClass, context, v, state, null); } @Override diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/AnonymousClassContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/AnonymousClassContext.java index f76eaf973ee..d3c5cbbb612 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/AnonymousClassContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/AnonymousClassContext.java @@ -22,9 +22,8 @@ import org.jetbrains.jet.codegen.OwnerKind; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLOSURE; +public class AnonymousClassContext extends ClassContext { -public class AnonymousClassContext extends CodegenContext { public AnonymousClassContext( @NotNull JetTypeMapper typeMapper, @NotNull ClassDescriptor contextDescriptor, @@ -33,14 +32,7 @@ public class AnonymousClassContext extends CodegenContext { @Nullable LocalLookup localLookup ) { //noinspection SuspiciousMethodCalls - super(contextDescriptor, contextKind, parentContext, typeMapper.getBindingContext().get(CLOSURE, contextDescriptor), - contextDescriptor, localLookup); - initOuterExpression(typeMapper, contextDescriptor); - } - - @Override - public boolean isStatic() { - return false; + super(typeMapper, contextDescriptor, contextKind, parentContext, localLookup); } @Override diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java index 14a55244cbc..efd84a550fa 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java @@ -146,31 +146,37 @@ public abstract class CodegenContext { return contextKind; } + @NotNull public CodegenContext intoNamespace(@NotNull NamespaceDescriptor descriptor) { return new NamespaceContext(descriptor, this, OwnerKind.NAMESPACE); } + @NotNull public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor) { return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo)); } + @NotNull public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null); } - public CodegenContext intoAnonymousClass( - ClassDescriptor descriptor, - ExpressionCodegen expressionCodegen + @NotNull + public ClassContext intoAnonymousClass( + @NotNull ClassDescriptor descriptor, + @NotNull ExpressionCodegen expressionCodegen ) { JetTypeMapper typeMapper = expressionCodegen.getState().getTypeMapper(); return new AnonymousClassContext(typeMapper, descriptor, OwnerKind.IMPLEMENTATION, this, expressionCodegen); } + @NotNull public MethodContext intoFunction(FunctionDescriptor descriptor) { return new MethodContext(descriptor, getContextKind(), this); } + @NotNull public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) { if (descriptor == null) { descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.emptyList(), true) @@ -180,6 +186,7 @@ public abstract class CodegenContext { return new ConstructorContext(descriptor, getContextKind(), this); } + @NotNull public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) { return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java index d9606affaf0..119d1e12ce3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor; import org.jetbrains.jet.codegen.signature.*; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; +import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; @@ -961,4 +962,15 @@ public class JetTypeMapper extends BindingTraceAware { } return new CallableMethod(owner, null, null, descriptor, INVOKEINTERFACE, owner, receiverParameterType, owner.getAsmType()); } + + @NotNull + public Type expressionType(JetExpression expr) { + JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr); + return asmTypeOrVoid(type); + } + + @NotNull + private Type asmTypeOrVoid(@Nullable JetType type) { + return type == null ? Type.VOID_TYPE : mapType(type); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index d56b23b3cff..1aa0917c074 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -553,6 +553,10 @@ public class JetPsiUtil { return getOutermostClassOrObject(classOrObject) == null; } + public static boolean isTrait(@NotNull JetClassOrObject classOrObject) { + return classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait(); + } + @Nullable public static JetClassOrObject getOutermostClassOrObject(@NotNull JetClassOrObject classOrObject) { JetClassOrObject current = classOrObject; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 84dd2283356..ede955951da 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetFunction; +import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; @@ -289,6 +290,10 @@ public class DescriptorUtils { return isKindOf(descriptor, ClassKind.ENUM_CLASS); } + public static boolean isClass(@NotNull DeclarationDescriptor descriptor) { + return isKindOf(descriptor, ClassKind.CLASS); + } + public static boolean isKindOf(@NotNull JetType jetType, @NotNull ClassKind classKind) { ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); return isKindOf(descriptor, classKind); @@ -572,4 +577,13 @@ public class DescriptorUtils { } return allSuperclasses; } + + @NotNull + public static PropertyDescriptor getPropertyDescriptor(@NotNull JetProperty property, @NotNull BindingContext bindingContext) { + VariableDescriptor descriptor = bindingContext.get(BindingContext.VARIABLE, property); + if (!(descriptor instanceof PropertyDescriptor)) { + throw new UnsupportedOperationException("expect a property to have a property descriptor"); + } + return (PropertyDescriptor) descriptor; + } }