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),
Kind.DECLARATION);
JetType receiverType = DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter());
setType(pd.getType(), Collections.<TypeParameterDescriptorImpl>emptyList(), pd.getExpectedThisObject(), receiverType);
boolean isStaticProperty = AsmUtil.isPropertyWithBackingFieldInOuterClass(pd)
&& !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));
}
@@ -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;
}
}
@@ -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<CodeChunk> staticInitializerChunks = new ArrayList<CodeChunk>();
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, "<clinit>", "()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, "<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() {
// generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator
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.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());
}
}
@@ -87,6 +87,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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) {
@@ -85,7 +85,7 @@ public abstract class FunctionGenerationStrategy<T extends CallableDescriptor> {
public abstract static class CodegenBased<T extends CallableDescriptor> extends FunctionGenerationStrategy<T> {
private final GenerationState state;
protected final GenerationState state;
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.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<PropertyDescriptor> 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<PropertyGetterDescriptor>(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<PropertySetterDescriptor>(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<ValueParameterDescriptor> 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<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
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<JetDeclaration> declarations,
@NotNull ExpressionCodegen codegen, @NotNull List<JetDeclaration> 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<PropertyDescriptor>();
}
classObjectPropertiesToCopy.add(descriptor);
}
}
@@ -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()) {
@@ -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.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<JetFile> 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);
@@ -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<PropertyAccessorDescriptor> {
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<PropertyAccessorDescriptor> {
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<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();
PropertyDescriptor property = descriptor.getCorrespondingProperty();
PropertyDescriptor property = callableDescriptor.getCorrespondingProperty();
Type asmType = typeMapper.mapType(property);
if (kind != OwnerKind.NAMESPACE) {
@@ -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);
@@ -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
@@ -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
@@ -146,31 +146,37 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
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.<AnnotationDescriptor>emptyList(), true)
@@ -180,6 +186,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
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);
}
@@ -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);
}
}
@@ -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;
@@ -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;
}
}