Realization of class object fields as static fields of outer class

#KT-2213 Fixed
This commit is contained in:
Mikhael Bogdanov
2013-05-21 14:23:38 +04:00
parent 47fe81471a
commit be72e096ef
18 changed files with 501 additions and 226 deletions
@@ -34,8 +34,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl {
pd.isVar(), Name.identifier(pd.getName() + "$b$" + index), pd.isVar(), Name.identifier(pd.getName() + "$b$" + index),
Kind.DECLARATION); Kind.DECLARATION);
JetType receiverType = DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter()); boolean isStaticProperty = AsmUtil.isPropertyWithBackingFieldInOuterClass(pd)
setType(pd.getType(), Collections.<TypeParameterDescriptorImpl>emptyList(), pd.getExpectedThisObject(), receiverType); && !AsmUtil.isClassObjectWithBackingFieldsInOuter(containingDeclaration);
JetType receiverType = !isStaticProperty ? DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter()) : null;
setType(pd.getType(), Collections.<TypeParameterDescriptorImpl>emptyList(), isStaticProperty ? null : pd.getExpectedThisObject(),
receiverType);
initialize(new Getter(this), new Setter(this)); initialize(new Getter(this), new Setter(this));
} }
@@ -30,7 +30,6 @@ import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*; 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.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 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.codegen.CodegenUtil.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; 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.isEnumEntry;
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.JAVA_STRING_TYPE;
public class AsmUtil { 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) { public static Type comparisonOperandType(Type left, Type right) {
if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE; 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.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE; if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
return Type.INT_TYPE; return Type.INT_TYPE;
} }
} }
@@ -17,9 +17,10 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; 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.codegen.state.GenerationState;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
@@ -40,12 +41,20 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
protected final OwnerKind kind; protected final OwnerKind kind;
protected final ClassDescriptor descriptor; protected final ClassDescriptor descriptor;
protected final ClassBuilder v; protected final ClassBuilder v;
protected final CodegenContext context; protected final ClassContext context;
protected final List<CodeChunk> staticInitializerChunks = new ArrayList<CodeChunk>(); private MethodVisitor clInitMethod;
protected ClassBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) { private ExpressionCodegen clInitCodegen;
super(state);
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); descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
myClass = aClass; myClass = aClass;
this.context = context; this.context = context;
@@ -53,7 +62,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
this.v = v; this.v = v;
} }
public final void generate() { public void generate() {
generateDeclaration(); generateDeclaration();
generateClassBody(); generateClassBody();
@@ -72,18 +81,20 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
private void generateClassBody() { private void generateClassBody() {
FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state); 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 //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts
if (shouldProcessFirst(declaration)) { for (JetDeclaration declaration : myClass.getDeclarations()) {
generateDeclaration(propertyCodegen, declaration, functionCodegen); if (shouldProcessFirst(declaration)) {
generateDeclaration(propertyCodegen, declaration);
}
} }
} }
for (JetDeclaration declaration : myClass.getDeclarations()) { for (JetDeclaration declaration : myClass.getDeclarations()) {
if (!shouldProcessFirst(declaration)) { 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); 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) { if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v); genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v);
} }
@@ -137,23 +149,39 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
} }
private void generateStaticInitializer() { private void generateStaticInitializer() {
if (staticInitializerChunks.size() > 0) { if (clInitMethod != null) {
MethodVisitor mv = v.newMethod(null, ACC_STATIC, "<clinit>", "()V", null, null); createOrGetClInitMethod();
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); ExpressionCodegen codegen = createOrGetClInitCodegen();
ExpressionCodegen codegen = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context, state); createOrGetClInitMethod().visitInsn(RETURN);
for (CodeChunk chunk : staticInitializerChunks) {
chunk.generate(codegen);
}
mv.visitInsn(RETURN);
FunctionCodegen.endVisit(codegen.v, "static initializer", myClass); FunctionCodegen.endVisit(codegen.v, "static initializer", myClass);
} }
} }
} }
@Nullable
protected MethodVisitor createOrGetClInitMethod() {
if (clInitMethod == null) {
clInitMethod = v.newMethod(null, ACC_STATIC, "<clinit>", "()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() { private void generateRemoveInIterator() {
// generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator // generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator
if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) { if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) {
@@ -27,6 +27,7 @@ import org.jetbrains.jet.codegen.context.NamespaceContext;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; 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.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
@@ -263,14 +264,26 @@ public class CodegenUtil {
return false; 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(); PropertyAccessorDescriptor accessorDescriptor = forGetter ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null; boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
boolean specialTypeProperty = isDelegated ||
isExtensionProperty ||
DescriptorUtils.isClassObject(propertyDescriptor.getContainingDeclaration()) ||
JetTypeMapper.isAccessor(propertyDescriptor);
return isInsideClass && return isInsideClass &&
!isDelegated && !specialTypeProperty &&
!isExtensionProperty &&
(accessorDescriptor == null || (accessorDescriptor == null ||
accessorDescriptor.isDefault() && accessorDescriptor.isDefault() &&
(!DescriptorUtils.isExternallyAccessible(propertyDescriptor) || accessorDescriptor.getModality() == Modality.FINAL)); (!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());
}
} }
@@ -87,6 +87,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private int myLastLineNumber = -1; private int myLastLineNumber = -1;
final InstructionAdapter v; final InstructionAdapter v;
final MethodVisitor methodVisitor;
final FrameMap myFrameMap; final FrameMap myFrameMap;
final JetTypeMapper typeMapper; final JetTypeMapper typeMapper;
@@ -121,8 +122,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
//noinspection SuspiciousMethodCalls //noinspection SuspiciousMethodCalls
CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor);
CodegenContext objectContext = context.intoAnonymousClass(classDescriptor, this); ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this);
ImplementationBodyCodegen implementationBodyCodegen = new ImplementationBodyCodegen(objectDeclaration, objectContext, classBuilder, state); ImplementationBodyCodegen implementationBodyCodegen = new ImplementationBodyCodegen(objectDeclaration, objectContext, classBuilder, state, null);
implementationBodyCodegen.generate(); implementationBodyCodegen.generate();
@@ -164,7 +165,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
this.typeMapper = state.getTypeMapper(); this.typeMapper = state.getTypeMapper();
this.returnType = returnType; this.returnType = returnType;
this.state = state; 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 @Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
super.visitLocalVariable(name, desc, signature, start, end, super.visitLocalVariable(name, desc, signature, start, end,
@@ -172,9 +181,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
localVariableNames.add(name); localVariableNames.add(name);
} }
}; };
this.bindingContext = state.getBindingContext();
this.context = context;
this.statementVisitor = new CodegenStatementVisitor(this);
} }
public GenerationState getState() { public GenerationState getState() {
@@ -275,9 +281,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
ClassBuilder classBuilder = state.getFactory().newVisitor(className.getInternalName(), declaration.getContainingFile() 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(); return StackValue.none();
} }
@@ -1673,26 +1679,26 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull @NotNull
public StackValue.Property intermediateValueForProperty( public StackValue.Property intermediateValueForProperty(
PropertyDescriptor propertyDescriptor, @NotNull PropertyDescriptor propertyDescriptor,
boolean forceField, boolean forceField,
@Nullable JetSuperExpression superExpression @Nullable JetSuperExpression superExpression
) { ) {
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false); return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL);
} }
@NotNull
public StackValue.Property intermediateValueForProperty( public StackValue.Property intermediateValueForProperty(
PropertyDescriptor propertyDescriptor, @NotNull PropertyDescriptor propertyDescriptor,
boolean forceField, boolean forceField,
@Nullable JetSuperExpression superExpression, @Nullable JetSuperExpression superExpression,
@NotNull boolean forceSpecialFlag @NotNull MethodKind methodKind
) { ) {
JetTypeMapper typeMapper = state.getTypeMapper(); JetTypeMapper typeMapper = state.getTypeMapper();
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
assert containingDeclaration != null; assert containingDeclaration != null;
boolean isStatic = containingDeclaration instanceof NamespaceDescriptor; boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
boolean isStatic = containingDeclaration instanceof NamespaceDescriptor || isBackingFieldInAnotherClass;
boolean isSuper = superExpression != null; boolean isSuper = superExpression != null;
boolean isInsideClass = isCallInsideSameClassAsDeclared(propertyDescriptor, context); boolean isInsideClass = isCallInsideSameClassAsDeclared(propertyDescriptor, context);
boolean isInsideModule = isCallInsideSameModuleAsDeclared(propertyDescriptor, context); boolean isInsideModule = isCallInsideSameModuleAsDeclared(propertyDescriptor, context);
@@ -1700,10 +1706,25 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
JetType delegateType = getPropertyDelegateType(propertyDescriptor, state.getBindingContext()); JetType delegateType = getPropertyDelegateType(propertyDescriptor, state.getBindingContext());
boolean isDelegatedProperty = delegateType != null; boolean isDelegatedProperty = delegateType != null;
CallableMethod callableGetter = null; CallableMethod callableGetter = null;
CallableMethod callableSetter = 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 //noinspection ConstantConditions
if (couldUseDirectAccessToProperty(propertyDescriptor, true, isInsideClass, isDelegatedProperty)) { if (couldUseDirectAccessToProperty(propertyDescriptor, true, isInsideClass, isDelegatedProperty)) {
callableGetter = null; callableGetter = null;
@@ -1721,7 +1742,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor); propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor);
if (propertyDescriptor.getGetter() != null) { 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<StackValue, StackValue> implem
callableSetter = null; callableSetter = null;
} }
else { 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<StackValue, StackValue> implem
propertyDescriptor = unwrapFakeOverride(propertyDescriptor); propertyDescriptor = unwrapFakeOverride(propertyDescriptor);
if (callableMethod == null) { if (callableMethod == null) {
owner = typeMapper.getOwner(propertyDescriptor, context.getContextKind(), isInsideModule); owner = typeMapper.getOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, context.getContextKind(), isInsideModule);
} }
else { else {
owner = callableMethod.getOwner(); owner = callableMethod.getOwner();
@@ -2316,8 +2339,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull @NotNull
public Type expressionType(JetExpression expr) { public Type expressionType(JetExpression expr) {
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr); return typeMapper.expressionType(expr);
return asmTypeOrVoid(type);
} }
public int indexOfLocal(JetReferenceExpression lhs) { public int indexOfLocal(JetReferenceExpression lhs) {
@@ -85,7 +85,7 @@ public abstract class FunctionGenerationStrategy<T extends CallableDescriptor> {
public abstract static class CodegenBased<T extends CallableDescriptor> extends FunctionGenerationStrategy<T> { public abstract static class CodegenBased<T extends CallableDescriptor> extends FunctionGenerationStrategy<T> {
private final GenerationState state; protected final GenerationState state;
protected final T callableDescriptor; protected final T callableDescriptor;
@@ -31,7 +31,7 @@ import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.binding.CodegenBinding; import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.binding.MutableClosure; 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.ConstructorContext;
import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.context.MethodContext;
import org.jetbrains.jet.codegen.signature.*; 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.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; 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.*;
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.JAVA_STRING_TYPE;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_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 Type classAsmType;
private final FunctionCodegen functionCodegen; private final FunctionCodegen functionCodegen;
private final PropertyCodegen propertyCodegen; private final PropertyCodegen propertyCodegen;
public ImplementationBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) { private List<PropertyDescriptor> classObjectPropertiesToCopy;
super(aClass, context, v, state);
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.classAsmType = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL);
this.functionCodegen = new FunctionCodegen(context, v, state); 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 @Override
@@ -429,6 +438,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
protected void generateSyntheticParts() { protected void generateSyntheticParts() {
generateFieldForSingleton(); generateFieldForSingleton();
generateClassObjectBackingFieldCopies();
try { try {
generatePrimaryConstructor(); generatePrimaryConstructor();
} }
@@ -446,7 +457,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateSyntheticAccessors(); generateSyntheticAccessors();
generateEnumMethods(); generateEnumMethodsAndConstInitializers();
generateFunctionsForDataClasses(); generateFunctionsForDataClasses();
@@ -750,25 +761,33 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
MethodContext functionContext = context.intoFunction(function); MethodContext functionContext = context.intoFunction(function);
FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION, FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION,
new DefaultParameterValueLoader() { new DefaultParameterValueLoader() {
@Override @Override
public void putValueOnStack( public void putValueOnStack(
ValueParameterDescriptor descriptor, ValueParameterDescriptor descriptor,
ExpressionCodegen codegen ExpressionCodegen codegen
) { ) {
assert (KotlinBuiltIns.getInstance() assert (KotlinBuiltIns.getInstance().isData((ClassDescriptor) function.getContainingDeclaration()))
.isData((ClassDescriptor) function.getContainingDeclaration())) : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation";
: "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(
PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get( BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor);
BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor); assert propertyDescriptor != null
assert propertyDescriptor != : "Trying to generate default value for parameter of copy function that doesn't correspond to any property";
null : "Trying to generate default value for parameter of copy function that doesn't correspond to any property"; codegen.v.load(0, thisDescriptorType);
codegen.v.load(0, thisDescriptorType); Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType());
Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType()); codegen.intermediateValueForProperty(propertyDescriptor, false, null).put(propertyType, codegen.v);
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() { private void generateEnumMethods() {
@@ -827,7 +846,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}); });
} }
else if (entry.getValue() instanceof PropertyDescriptor) { else if (entry.getValue() instanceof PropertyDescriptor) {
PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue(); final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
final PropertyDescriptor original = (PropertyDescriptor) entry.getKey(); final PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
@@ -837,9 +856,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
new FunctionGenerationStrategy.CodegenBased<PropertyGetterDescriptor>(state, getter) { new FunctionGenerationStrategy.CodegenBased<PropertyGetterDescriptor>(state, getter) {
@Override @Override
public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) {
StackValue.Property property = codegen.intermediateValueForProperty(original, false, null, true);
InstructionAdapter iv = codegen.v; 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); property.put(property.type, iv);
iv.areturn(signature.getAsmMethod().getReturnType()); iv.areturn(signature.getAsmMethod().getReturnType());
} }
@@ -854,12 +876,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
new FunctionGenerationStrategy.CodegenBased<PropertySetterDescriptor>(state, setter) { new FunctionGenerationStrategy.CodegenBased<PropertySetterDescriptor>(state, setter) {
@Override @Override
public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { 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; InstructionAdapter iv = codegen.v;
iv.load(0, OBJECT_TYPE);
Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); 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]; Type argType = argTypes[i];
iv.load(reg, argType); iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter //noinspection AssignmentToForLoopParameter
@@ -915,22 +937,64 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (!(isNonLiteralObject(myClass) || hasClassObject) || isEnumClass) return; if (!(isNonLiteralObject(myClass) || hasClassObject) || isEnumClass) return;
final ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor; ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor;
assert fieldTypeDescriptor != null; 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; JetClassOrObject original = hasClassObject ? ((JetClass) myClass).getClassObject().getObjectDeclaration() : myClass;
v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null); v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
staticInitializerChunks.add(new CodeChunk() { if (!AsmUtil.isClassObjectWithBackingFieldsInOuter(fieldTypeDescriptor)) {
@Override genInitSingleton(fieldTypeDescriptor, field);
public void generate(ExpressionCodegen codegen) { }
ConstructorDescriptor constructorDescriptor = DescriptorUtils.getConstructorOfSingletonObject(fieldTypeDescriptor); }
FunctionDescriptor fd = codegen.accessableFunctionDescriptor(constructorDescriptor);
generateMethodCallTo(fd, codegen.v); private void generateClassObjectBackingFieldCopies() {
field.store(field.type, codegen.v); 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() { protected void generatePrimaryConstructor() {
@@ -981,9 +1045,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
private void generatePrimaryConstructorImpl( private void generatePrimaryConstructorImpl(
ConstructorDescriptor constructorDescriptor, @Nullable ConstructorDescriptor constructorDescriptor,
ExpressionCodegen codegen, @NotNull final ExpressionCodegen codegen,
MutableClosure closure @Nullable MutableClosure closure
) { ) {
List<ValueParameterDescriptor> paramDescrs = constructorDescriptor != null List<ValueParameterDescriptor> paramDescrs = constructorDescriptor != null
? constructorDescriptor.getValueParameters() ? constructorDescriptor.getValueParameters()
@@ -1035,7 +1099,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
curParam++; 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); iv.visitInsn(RETURN);
} }
@@ -1225,7 +1299,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
private void generateTraitMethods() { private void generateTraitMethods() {
if (myClass instanceof JetClass && ((JetClass) myClass).isTrait()) { if (JetPsiUtil.isTrait(myClass)) {
return; return;
} }
@@ -1425,29 +1499,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @Override
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) {
if (declaration instanceof JetEnumEntry) { if (declaration instanceof JetEnumEntry) {
String name = declaration.getName(); String name = declaration.getName();
String desc = "L" + classAsmType.getInternalName() + ";"; String desc = "L" + classAsmType.getInternalName() + ";";
v.newField(declaration, ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null); 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); myEnumConstants.add((JetEnumEntry) declaration);
} }
super.generateDeclaration(propertyCodegen, declaration, functionCodegen); super.generateDeclaration(propertyCodegen, declaration);
} }
private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>(); private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
private void initializeEnumConstants(InstructionAdapter iv) { private void initializeEnumConstants(ExpressionCodegen codegen) {
ExpressionCodegen codegen = new ExpressionCodegen(iv, new FrameMap(), Type.VOID_TYPE, context, state); InstructionAdapter iv = codegen.v;
int ordinal = -1; int ordinal = -1;
JetType myType = descriptor.getDefaultType(); JetType myType = descriptor.getDefaultType();
Type myAsmType = typeMapper.mapType(myType, JetTypeMapperMode.IMPL); Type myAsmType = typeMapper.mapType(myType, JetTypeMapperMode.IMPL);
@@ -1509,14 +1575,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
public static void generateInitializers( public static void generateInitializers(
@NotNull ExpressionCodegen codegen, @NotNull InstructionAdapter iv, @NotNull List<JetDeclaration> declarations, @NotNull ExpressionCodegen codegen, @NotNull List<JetDeclaration> declarations,
@NotNull BindingContext bindingContext, @NotNull GenerationState state @NotNull BindingContext bindingContext, @NotNull GenerationState state
) { ) {
JetTypeMapper typeMapper = state.getTypeMapper(); JetTypeMapper typeMapper = state.getTypeMapper();
for (JetDeclaration declaration : declarations) { for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) { if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
initializeProperty(codegen, bindingContext, iv, (JetProperty) declaration, false); initializeProperty(codegen, bindingContext, (JetProperty) declaration);
} }
} }
else if (declaration instanceof JetClassInitializer) { else if (declaration instanceof JetClassInitializer) {
@@ -1525,16 +1591,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
public static void initializeProperty( public static void initializeProperty(
@NotNull ExpressionCodegen codegen, @NotNull ExpressionCodegen codegen,
@NotNull BindingContext bindingContext, @NotNull BindingContext bindingContext,
@NotNull InstructionAdapter iv, @NotNull JetProperty property
@NotNull JetProperty property,
boolean isStatic
) { ) {
if (!isStatic) {
iv.load(0, OBJECT_TYPE);
}
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property); PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
assert propertyDescriptor != null; assert propertyDescriptor != null;
@@ -1543,14 +1605,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
JetType jetType = getPropertyOrDelegateType(bindingContext, property, propertyDescriptor); 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); Type type = codegen.expressionType(initializer);
if (jetType.isNullable()) { if (jetType.isNullable()) {
type = boxType(type); type = boxType(type);
} }
codegen.gen(initializer, type); codegen.gen(initializer, type);
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null); propValue.store(type, codegen.v);
propValue.store(type, iv);
} }
public static boolean shouldInitializeProperty( public static boolean shouldInitializeProperty(
@@ -1699,4 +1767,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return r; return r;
} }
public void addClassObjectPropertyToCopy(PropertyDescriptor descriptor) {
if (classObjectPropertiesToCopy == null) {
classObjectPropertiesToCopy = new ArrayList<PropertyDescriptor>();
}
classObjectPropertiesToCopy.add(descriptor);
}
} }
@@ -17,22 +17,32 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull; 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.context.CodegenContext;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStateAware; import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.ErrorUtils; 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 class MemberCodegen extends GenerationStateAware {
public MemberCodegen(@NotNull GenerationState state) {
@Nullable
private MemberCodegen parentCodegen;
public MemberCodegen(@NotNull GenerationState state, @Nullable MemberCodegen parentCodegen) {
super(state); super(state);
this.parentCodegen = parentCodegen;
}
@Nullable
public MemberCodegen getParentCodegen() {
return parentCodegen;
} }
public void genFunctionOrProperty( public void genFunctionOrProperty(
@@ -54,7 +64,7 @@ public class MemberCodegen extends GenerationStateAware {
} }
else if (functionOrProperty instanceof JetProperty) { else if (functionOrProperty instanceof JetProperty) {
try { try {
new PropertyCodegen(context, classBuilder, functionCodegen).gen((JetProperty) functionOrProperty); new PropertyCodegen(context, classBuilder, functionCodegen, this).gen((JetProperty) functionOrProperty);
} }
catch (CompilationException e) { catch (CompilationException e) {
throw e; throw e;
@@ -80,8 +90,8 @@ public class MemberCodegen extends GenerationStateAware {
} }
ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile()); ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile());
CodegenContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state); ClassContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate(); new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, this).generate();
classBuilder.done(); classBuilder.done();
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) { if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
@@ -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
}
@@ -26,11 +26,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; 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.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -56,7 +54,7 @@ public class NamespaceCodegen extends MemberCodegen {
GenerationState state, GenerationState state,
Collection<JetFile> namespaceFiles Collection<JetFile> namespaceFiles
) { ) {
super(state); super(state, null);
checkAllFilesHaveSameNamespace(namespaceFiles); checkAllFilesHaveSameNamespace(namespaceFiles);
this.v = v; this.v = v;
@@ -218,7 +216,7 @@ public class NamespaceCodegen extends MemberCodegen {
for (JetDeclaration declaration : properties) { for (JetDeclaration declaration : properties) {
ImplementationBodyCodegen. ImplementationBodyCodegen.
initializeProperty(codegen, state.getBindingContext(), new InstructionAdapter(mv), (JetProperty) declaration, true); initializeProperty(codegen, state.getBindingContext(), (JetProperty) declaration);
} }
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
@@ -19,24 +19,29 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.FieldVisitor; import org.jetbrains.asm4.FieldVisitor;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; 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.CodegenContext;
import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.context.MethodContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; 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.GenerationStateAware;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorResolver; 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.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; 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.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
import org.jetbrains.jet.lang.resolve.name.Name; 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.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.getDeprecatedAccessFlag; 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.codegen.CodegenUtil.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
public class PropertyCodegen extends GenerationStateAware { public class PropertyCodegen extends GenerationStateAware {
@NotNull
private final FunctionCodegen functionCodegen; private final FunctionCodegen functionCodegen;
@NotNull
private final ClassBuilder v; private final ClassBuilder v;
@NotNull
private final CodegenContext context; private final CodegenContext context;
@Nullable
private MemberCodegen classBodyCodegen;
@NotNull
private final OwnerKind kind; 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()); super(functionCodegen.getState());
this.v = v; this.v = v;
this.functionCodegen = functionCodegen; this.functionCodegen = functionCodegen;
this.context = context; this.context = context;
this.classBodyCodegen = classBodyCodegen;
this.kind = context.getContextKind(); this.kind = context.getContextKind();
} }
public void gen(JetProperty p) { public void gen(JetProperty p) {
VariableDescriptor descriptor = bindingContext.get(BindingContext.VARIABLE, p); PropertyDescriptor propertyDescriptor = DescriptorUtils.getPropertyDescriptor(p, bindingContext);
if (!(descriptor instanceof PropertyDescriptor)) {
throw new UnsupportedOperationException("expect a property to have a property descriptor");
}
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
assert kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL 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)) { if (kind != OwnerKind.TRAIT_IMPL && !(kind instanceof OwnerKind.StaticDelegateKind)) {
generateBackingField(p, propertyDescriptor); 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 //noinspection ConstantConditions
boolean hasBackingField = bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); boolean hasBackingField = bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
boolean isDelegated = p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null; 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) { private FieldVisitor generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) {
int modifiers = ACC_PRIVATE | ACC_FINAL | getDeprecatedAccessFlag(propertyDescriptor); int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
if (kind == OwnerKind.NAMESPACE) {
modifiers |= ACC_STATIC;
}
if (KotlinBuiltIns.getInstance().isVolatile(propertyDescriptor)) { if (KotlinBuiltIns.getInstance().isVolatile(propertyDescriptor)) {
modifiers |= ACC_VOLATILE; 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()); JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, p.getDelegateExpression());
if (delegateType == null) { if (delegateType == null) {
// If delegate expression is unresolved reference // If delegate expression is unresolved reference
delegateType = ErrorUtils.createErrorType("Delegate type"); delegateType = ErrorUtils.createErrorType("Delegate type");
} }
Type type = typeMapper.mapType(delegateType);
return v.newField(p, modifiers, JvmAbi.getPropertyDelegateName(propertyDescriptor.getName()), type.getDescriptor(), return generateBackingField(p, propertyDescriptor, true, delegateType, null);
null, null);
} }
private FieldVisitor generateBackingFieldAccess(PsiElement p, PropertyDescriptor propertyDescriptor) { private FieldVisitor generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) {
Object value = null; Object value = null;
if (p instanceof JetProperty && !ImplementationBodyCodegen.shouldInitializeProperty((JetProperty) p, typeMapper)) { if (p instanceof JetProperty && !ImplementationBodyCodegen.shouldInitializeProperty((JetProperty) p, typeMapper)) {
JetExpression initializer = ((JetProperty) p).getInitializer(); JetExpression initializer = ((JetProperty) p).getInitializer();
@@ -135,22 +184,8 @@ public class PropertyCodegen extends GenerationStateAware {
value = compileTimeValue != null ? compileTimeValue.getValue() : null; value = compileTimeValue != null ? compileTimeValue.getValue() : null;
} }
} }
int modifiers;
if (kind == OwnerKind.NAMESPACE) { return generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value);
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);
} }
private void generateGetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor getter) { private void generateGetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor getter) {
@@ -166,10 +201,10 @@ public class PropertyCodegen extends GenerationStateAware {
FunctionGenerationStrategy strategy; FunctionGenerationStrategy strategy;
if (defaultGetter) { if (defaultGetter) {
if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) { if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) {
strategy = new DefaultPropertyWithDelegateAccessorStrategy(getterDescriptor); strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, getterDescriptor);
} }
else { else {
strategy = new DefaultPropertyAccessorStrategy(getterDescriptor); strategy = new DefaultPropertyAccessorStrategy(state, getterDescriptor);
} }
} }
else { else {
@@ -197,10 +232,10 @@ public class PropertyCodegen extends GenerationStateAware {
FunctionGenerationStrategy strategy; FunctionGenerationStrategy strategy;
if (defaultSetter) { if (defaultSetter) {
if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) { if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) {
strategy = new DefaultPropertyWithDelegateAccessorStrategy(setterDescriptor); strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, setterDescriptor);
} }
else { else {
strategy = new DefaultPropertyAccessorStrategy(setterDescriptor); strategy = new DefaultPropertyAccessorStrategy(state, setterDescriptor);
} }
} }
else { else {
@@ -216,90 +251,82 @@ public class PropertyCodegen extends GenerationStateAware {
} }
private class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy { private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
private final PropertyAccessorDescriptor descriptor;
public DefaultPropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor descriptor) { public DefaultPropertyAccessorStrategy(
this.descriptor = descriptor; @NotNull GenerationState state,
@NotNull PropertyAccessorDescriptor callableDescriptor
) {
super(state, callableDescriptor);
} }
@Override @Override
public void generateBody( public void doGenerateBody(
@NotNull MethodVisitor mv, ExpressionCodegen codegen, JvmMethodSignature signature
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context
) { ) {
generateDefaultAccessor(descriptor, new InstructionAdapter(mv), typeMapper, context); generateDefaultAccessor(callableDescriptor, codegen.v, codegen);
} }
} }
private static void generateDefaultAccessor( private static void generateDefaultAccessor(
@NotNull PropertyAccessorDescriptor accessorDescriptor, @NotNull PropertyAccessorDescriptor accessorDescriptor,
@NotNull InstructionAdapter iv, @NotNull InstructionAdapter iv,
@NotNull JetTypeMapper typeMapper, @NotNull ExpressionCodegen codegen
@NotNull CodegenContext context
) { ) {
JetTypeMapper typeMapper = codegen.typeMapper;
CodegenContext context = codegen.context;
OwnerKind kind = context.getContextKind(); OwnerKind kind = context.getContextKind();
PropertyDescriptor propertyDescriptor = accessorDescriptor.getCorrespondingProperty(); PropertyDescriptor propertyDescriptor = accessorDescriptor.getCorrespondingProperty();
Type type = typeMapper.mapType(propertyDescriptor); 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 (accessorDescriptor instanceof PropertyGetterDescriptor) {
if (kind != OwnerKind.NAMESPACE) { property.put(type, iv);
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());
iv.areturn(type); iv.areturn(type);
} }
else if (accessorDescriptor instanceof PropertySetterDescriptor) { else if (accessorDescriptor instanceof PropertySetterDescriptor) {
int paramCode = 0;
if (kind != OwnerKind.NAMESPACE) {
iv.load(0, OBJECT_TYPE);
paramCode = 1;
}
ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter(); ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter();
if (receiverParameter != null) { if (receiverParameter != null) {
paramCode += typeMapper.mapType(receiverParameter.getType()).getSize(); paramCode += typeMapper.mapType(receiverParameter.getType()).getSize();
} }
iv.load(paramCode, type); 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); iv.visitInsn(RETURN);
} else { } else {
assert false : "Unreachable state"; assert false : "Unreachable state";
} }
} }
private class DefaultPropertyWithDelegateAccessorStrategy extends FunctionGenerationStrategy { private static class DefaultPropertyWithDelegateAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
private final PropertyAccessorDescriptor descriptor; public DefaultPropertyWithDelegateAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
super(state, descriptor);
public DefaultPropertyWithDelegateAccessorStrategy(@NotNull PropertyAccessorDescriptor descriptor) {
this.descriptor = descriptor;
} }
@Override @Override
public void generateBody( public void doGenerateBody(
@NotNull MethodVisitor mv, @NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context
) { ) {
InstructionAdapter iv = new InstructionAdapter(mv); JetTypeMapper typeMapper = codegen.typeMapper;
ExpressionCodegen codegen = new ExpressionCodegen( OwnerKind kind = codegen.context.getContextKind();
mv, getFrameMap(typeMapper, context), signature.getAsmMethod().getReturnType(), context, state); InstructionAdapter iv = codegen.v;
BindingContext bindingContext = state.getBindingContext();
ResolvedCall<FunctionDescriptor> resolvedCall = ResolvedCall<FunctionDescriptor> 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(); 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); Type asmType = typeMapper.mapType(property);
if (kind != OwnerKind.NAMESPACE) { if (kind != OwnerKind.NAMESPACE) {
@@ -53,7 +53,7 @@ public class ScriptCodegen extends MemberCodegen {
private Method scriptConstructorMethod; private Method scriptConstructorMethod;
public ScriptCodegen(@NotNull GenerationState state) { public ScriptCodegen(@NotNull GenerationState state) {
super(state); super(state, null);
} }
@Inject @Inject
@@ -145,7 +145,6 @@ public class ScriptCodegen extends MemberCodegen {
ImplementationBodyCodegen.generateInitializers( ImplementationBodyCodegen.generateInitializers(
new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state), new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state),
instructionAdapter,
scriptDeclaration.getDeclarations(), scriptDeclaration.getDeclarations(),
bindingContext, bindingContext,
state); state);
@@ -16,7 +16,7 @@
package org.jetbrains.jet.codegen; 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.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapperMode; import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.psi.JetClassOrObject; import org.jetbrains.jet.lang.psi.JetClassOrObject;
@@ -24,8 +24,8 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
public class TraitImplBodyCodegen extends ClassBodyCodegen { public class TraitImplBodyCodegen extends ClassBodyCodegen {
public TraitImplBodyCodegen(JetClassOrObject aClass, CodegenContext context, ClassBuilder v, GenerationState state) { public TraitImplBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassBuilder v, GenerationState state) {
super(aClass, context, v, state); super(aClass, context, v, state, null);
} }
@Override @Override
@@ -22,9 +22,8 @@ import org.jetbrains.jet.codegen.OwnerKind;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 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( public AnonymousClassContext(
@NotNull JetTypeMapper typeMapper, @NotNull JetTypeMapper typeMapper,
@NotNull ClassDescriptor contextDescriptor, @NotNull ClassDescriptor contextDescriptor,
@@ -33,14 +32,7 @@ public class AnonymousClassContext extends CodegenContext {
@Nullable LocalLookup localLookup @Nullable LocalLookup localLookup
) { ) {
//noinspection SuspiciousMethodCalls //noinspection SuspiciousMethodCalls
super(contextDescriptor, contextKind, parentContext, typeMapper.getBindingContext().get(CLOSURE, contextDescriptor), super(typeMapper, contextDescriptor, contextKind, parentContext, localLookup);
contextDescriptor, localLookup);
initOuterExpression(typeMapper, contextDescriptor);
}
@Override
public boolean isStatic() {
return false;
} }
@Override @Override
@@ -146,31 +146,37 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
return contextKind; return contextKind;
} }
@NotNull
public CodegenContext intoNamespace(@NotNull NamespaceDescriptor descriptor) { public CodegenContext intoNamespace(@NotNull NamespaceDescriptor descriptor) {
return new NamespaceContext(descriptor, this, OwnerKind.NAMESPACE); return new NamespaceContext(descriptor, this, OwnerKind.NAMESPACE);
} }
@NotNull
public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor) { public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor) {
return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo)); return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo));
} }
@NotNull
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null); return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
} }
public CodegenContext intoAnonymousClass( @NotNull
ClassDescriptor descriptor, public ClassContext intoAnonymousClass(
ExpressionCodegen expressionCodegen @NotNull ClassDescriptor descriptor,
@NotNull ExpressionCodegen expressionCodegen
) { ) {
JetTypeMapper typeMapper = expressionCodegen.getState().getTypeMapper(); JetTypeMapper typeMapper = expressionCodegen.getState().getTypeMapper();
return new AnonymousClassContext(typeMapper, descriptor, OwnerKind.IMPLEMENTATION, this, return new AnonymousClassContext(typeMapper, descriptor, OwnerKind.IMPLEMENTATION, this,
expressionCodegen); expressionCodegen);
} }
@NotNull
public MethodContext intoFunction(FunctionDescriptor descriptor) { public MethodContext intoFunction(FunctionDescriptor descriptor) {
return new MethodContext(descriptor, getContextKind(), this); return new MethodContext(descriptor, getContextKind(), this);
} }
@NotNull
public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) { public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) {
if (descriptor == null) { if (descriptor == null) {
descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true) descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true)
@@ -180,6 +186,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
return new ConstructorContext(descriptor, getContextKind(), this); return new ConstructorContext(descriptor, getContextKind(), this);
} }
@NotNull
public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) { public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) {
return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
} }
@@ -28,6 +28,7 @@ import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
import org.jetbrains.jet.codegen.signature.*; import org.jetbrains.jet.codegen.signature.*;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; 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.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; 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()); 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);
}
} }
@@ -553,6 +553,10 @@ public class JetPsiUtil {
return getOutermostClassOrObject(classOrObject) == null; return getOutermostClassOrObject(classOrObject) == null;
} }
public static boolean isTrait(@NotNull JetClassOrObject classOrObject) {
return classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait();
}
@Nullable @Nullable
public static JetClassOrObject getOutermostClassOrObject(@NotNull JetClassOrObject classOrObject) { public static JetClassOrObject getOutermostClassOrObject(@NotNull JetClassOrObject classOrObject) {
JetClassOrObject current = classOrObject; JetClassOrObject current = classOrObject;
@@ -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.descriptors.impl.NamespaceDescriptorParent;
import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetFunction; 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.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
@@ -289,6 +290,10 @@ public class DescriptorUtils {
return isKindOf(descriptor, ClassKind.ENUM_CLASS); 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) { public static boolean isKindOf(@NotNull JetType jetType, @NotNull ClassKind classKind) {
ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
return isKindOf(descriptor, classKind); return isKindOf(descriptor, classKind);
@@ -572,4 +577,13 @@ public class DescriptorUtils {
} }
return allSuperclasses; 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;
}
} }