Synthetic accessors for class object private members

#KT-3338 Fixed
This commit is contained in:
Mikhael Bogdanov
2013-06-10 18:14:05 +04:00
parent 4ef2f997ed
commit 47fe81471a
32 changed files with 542 additions and 146 deletions
@@ -30,6 +30,7 @@ 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;
@@ -48,6 +49,7 @@ import java.util.Set;
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.java.AsmTypeConstants.JAVA_STRING_TYPE;
public class AsmUtil {
@@ -239,15 +241,13 @@ public class AsmUtil {
return null;
}
// the following code is only for PRIVATE visibility of member
if (isClassObject(containingDeclaration)) {
if (isEnumEntry(memberDescriptor)) {
return NO_FLAG_PACKAGE_PRIVATE;
}
if (memberDescriptor instanceof ConstructorDescriptor) {
ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
if (kind == ClassKind.OBJECT) {
//TODO: should be NO_FLAG_PACKAGE_PRIVATE
// see http://youtrack.jetbrains.com/issue/KT-2700
return ACC_PUBLIC;
return NO_FLAG_PACKAGE_PRIVATE;
}
else if (kind == ClassKind.ENUM_ENTRY) {
return NO_FLAG_PACKAGE_PRIVATE;
@@ -105,10 +105,14 @@ public class CallableMethod implements Callable {
@NotNull GenerationState state,
@NotNull ResolvedCall resolvedCall
) {
invoke(v);
invokeWithoutAssertions(v);
AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall);
}
public void invokeWithoutAssertions(@NotNull InstructionAdapter v) {
invoke(v);
}
@Nullable
public Type getGenerateCalleeType() {
return generateCalleeType;
@@ -19,7 +19,6 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
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.ClassDescriptor;
@@ -76,12 +75,25 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen);
for (JetDeclaration declaration : myClass.getDeclarations()) {
generateDeclaration(propertyCodegen, declaration, functionCodegen);
//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, functionCodegen);
}
}
generatePrimaryConstructorProperties(propertyCodegen, myClass);
}
private boolean shouldProcessFirst(JetDeclaration declaration) {
return false == (declaration instanceof JetProperty || declaration instanceof JetNamedFunction);
}
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v);
@@ -126,18 +138,18 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
private void generateStaticInitializer() {
if (staticInitializerChunks.size() > 0) {
MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
MethodVisitor mv = v.newMethod(null, ACC_STATIC, "<clinit>", "()V", null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context, state);
for (CodeChunk chunk : staticInitializerChunks) {
chunk.generate(v);
chunk.generate(codegen);
}
mv.visitInsn(RETURN);
FunctionCodegen.endVisit(v, "static initializer", myClass);
FunctionCodegen.endVisit(codegen.v, "static initializer", myClass);
}
}
}
@@ -16,8 +16,6 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.asm4.commons.InstructionAdapter;
public interface CodeChunk {
void generate(InstructionAdapter v);
void generate(ExpressionCodegen codegen);
}
@@ -1562,7 +1562,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
JetExpression r = getReceiverForSelector(expression);
boolean isSuper = r instanceof JetSuperExpression;
propertyDescriptor = accessablePropertyDescriptor(context, propertyDescriptor);
propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor);
StackValue.Property iValue =
intermediateValueForProperty(propertyDescriptor, directToField, isSuper ? (JetSuperExpression) r : null);
if (directToField) {
@@ -1677,16 +1677,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
boolean forceField,
@Nullable JetSuperExpression superExpression
) {
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, state, context, false);
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false);
}
@NotNull
public static StackValue.Property intermediateValueForProperty(
public StackValue.Property intermediateValueForProperty(
PropertyDescriptor propertyDescriptor,
boolean forceField,
@Nullable JetSuperExpression superExpression,
@NotNull GenerationState state,
@NotNull CodegenContext context,
@NotNull boolean forceSpecialFlag
) {
JetTypeMapper typeMapper = state.getTypeMapper();
@@ -1720,7 +1718,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
propertyDescriptor = accessablePropertyDescriptor(context, propertyDescriptor);
propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor);
if (propertyDescriptor.getGetter() != null) {
callableGetter = typeMapper.mapToCallableMethod(propertyDescriptor.getGetter(), isSuper || forceSpecialFlag, isInsideClass, isInsideModule, OwnerKind.IMPLEMENTATION);
@@ -1854,47 +1852,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
private static PropertyDescriptor accessablePropertyDescriptor(CodegenContext context, PropertyDescriptor propertyDescriptor) {
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
int flag = getVisibilityAccessFlag(propertyDescriptor) |
(getter == null ? 0 : getVisibilityAccessFlag(getter)) |
(setter == null ? 0 : getVisibilityAccessFlag(setter));
if ((flag & ACC_PRIVATE) == 0) {
return propertyDescriptor;
}
return (PropertyDescriptor) accessibleDescriptor(context, propertyDescriptor);
@NotNull
private PropertyDescriptor accessablePropertyDescriptor(PropertyDescriptor propertyDescriptor) {
return context.accessablePropertyDescriptor(propertyDescriptor);
}
private FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) {
int flag = getVisibilityAccessFlag(fd);
if ((flag & ACC_PRIVATE) == 0) {
return fd;
}
return (FunctionDescriptor) accessibleDescriptor(context, fd);
}
private static MemberDescriptor accessibleDescriptor(CodegenContext context, DeclarationDescriptor descriptor) {
if (context.getClassOrNamespaceDescriptor() != descriptor.getContainingDeclaration()) {
DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
if (context.hasThisDescriptor() && enclosed != context.getThisDescriptor()) {
CodegenContext c = context;
while (c.getContextDescriptor() != enclosed) {
c = c.getParentContext();
if (c == null) {
return (MemberDescriptor) descriptor;
}
}
return (MemberDescriptor) c.getAccessor(descriptor);
}
}
return (MemberDescriptor) descriptor;
@NotNull
protected FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) {
return context.accessableFunctionDescriptor(fd);
}
@NotNull
public StackValue invokeFunction(
Call call,
StackValue receiver,
@@ -1943,7 +1911,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
@Nullable
private static JetSuperExpression getSuperCallExpression(Call call) {
private static JetSuperExpression getSuperCallExpression(@NotNull Call call) {
ReceiverValue explicitReceiver = call.getExplicitReceiver();
if (explicitReceiver instanceof ExpressionReceiver) {
JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression();
@@ -1954,7 +1922,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return null;
}
private static boolean isSuperCall(Call call) {
private static boolean isSuperCall(@NotNull Call call) {
return getSuperCallExpression(call) != null;
}
@@ -1972,6 +1940,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
@NotNull
private StackValue returnValueAsStackValue(FunctionDescriptor fd, Type callReturnType) {
if (callReturnType != Type.VOID_TYPE) {
JetType type = fd.getReturnType();
@@ -37,6 +37,7 @@ import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter;
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.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
@@ -132,6 +133,8 @@ public class FunctionCodegen extends GenerationStateAware {
endVisit(mv, null, origin);
generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor);
methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, typeMapper);
}
@Nullable
@@ -180,7 +183,9 @@ public class FunctionCodegen extends GenerationStateAware {
labelsForSharedVars.putAll(createSharedVarsForParameters(mv, functionDescriptor, frameMap));
genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
if (!JetTypeMapper.isAccessor(functionDescriptor)) {
genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
}
strategy.generateBody(mv, signature, context);
@@ -750,22 +750,25 @@ 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 generateEnumMethods() {
@@ -802,8 +805,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private void generateSyntheticAccessors() {
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : context.getAccessors().entrySet()) {
protected void generateSyntheticAccessors() {
Map<DeclarationDescriptor, DeclarationDescriptor> accessors = context.getAccessors();
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) {
generateSyntheticAccessor(entry);
}
}
@@ -811,51 +815,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) {
if (entry.getValue() instanceof FunctionDescriptor) {
FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue();
FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
final FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
functionCodegen.generateMethod(null, typeMapper.mapSignature(bridge), false, bridge,
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) {
@Override
public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) {
generateMethodCallTo(original, codegen.v);
Method method = typeMapper.mapSignature(bridge).getAsmMethod();
boolean isConstructor = original instanceof ConstructorDescriptor;
Method originalMethod = isConstructor ?
typeMapper.mapConstructorSignature((ConstructorDescriptor) original).getAsmMethod() :
typeMapper.mapSignature(original).getAsmMethod();
Type[] argTypes = method.getArgumentTypes();
String owner = typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION, isCallInsideSameModuleAsDeclared(original, context)).getInternalName();
MethodVisitor mv = v.newMethod(null, ACC_SYNTHETIC | ACC_STATIC, bridge.getName().asString(),
method.getDescriptor(), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
genStubCode(mv);
}
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
if (isConstructor) {
iv.anew(method.getReturnType());
iv.dup();
}
else {
// todo: note that for now we never have access bridges for namespace methods, if at some point we do...
iv.load(0, OBJECT_TYPE);
}
for (int i = isConstructor ? 0 : 1, reg = isConstructor ? 0 : 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
iv.invokespecial(owner, originalMethod.getName(), originalMethod.getDescriptor());
iv.areturn(method.getReturnType());
FunctionCodegen.endVisit(iv, "accessor", null);
}
codegen.v.areturn(signature.getAsmMethod().getReturnType());
}
});
}
else if (entry.getValue() instanceof PropertyDescriptor) {
PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
final PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
final StackValue.Property property = ExpressionCodegen.intermediateValueForProperty(original, false, null, state, context, true);
PropertyGetterDescriptor getter = bridge.getGetter();
assert getter != null;
@@ -863,6 +837,7 @@ 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);
property.put(property.type, iv);
@@ -879,6 +854,7 @@ 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);
InstructionAdapter iv = codegen.v;
iv.load(0, OBJECT_TYPE);
@@ -901,23 +877,58 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private void generateMethodCallTo(FunctionDescriptor functionDescriptor, InstructionAdapter iv) {
boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor;
boolean callFromAccessor = !JetTypeMapper.isAccessor(functionDescriptor);
CallableMethod callableMethod = isConstructor ?
typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) :
typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor,
isCallInsideSameClassAsDeclared(functionDescriptor, context),
isCallInsideSameModuleAsDeclared(functionDescriptor, context),
context.getContextKind());
Method method = callableMethod.getSignature().getAsmMethod();
Type[] argTypes = method.getArgumentTypes();
int reg = 1;
if (isConstructor) {
iv.anew(callableMethod.getOwner().getAsmType());
iv.dup();
reg = 0;
}
else if (callFromAccessor) {
iv.load(0, OBJECT_TYPE);
}
for (int paramIndex = 0; paramIndex < argTypes.length; paramIndex++) {
Type argType = argTypes[paramIndex];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
callableMethod.invokeWithoutAssertions(iv);
}
private void generateFieldForSingleton() {
boolean hasClassObject = descriptor.getClassObjectDescriptor() != null;
boolean isEnumClass = DescriptorUtils.isEnumClass(descriptor);
if (!(isNonLiteralObject(myClass) || hasClassObject) || isEnumClass) return;
ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor;
final ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor;
assert fieldTypeDescriptor != null;
final FieldInfo info = FieldInfo.createForSingleton(fieldTypeDescriptor, typeMapper);
final StackValue.Field field = StackValue.singleton(fieldTypeDescriptor, typeMapper);
JetClassOrObject original = hasClassObject ? ((JetClass) myClass).getClassObject().getObjectDeclaration() : myClass;
v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, info.getFieldName(), info.getFieldType().getDescriptor(), null, null);
v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter iv) {
genInitSingletonField(info, iv);
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);
}
});
}
@@ -963,6 +974,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, closure);
FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v);
if (isClassObject(descriptor)) {
context.recordSyntheticAccessorIfNeeded(constructorDescriptor, typeMapper);
}
}
private void generatePrimaryConstructorImpl(
@@ -1418,8 +1433,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (myEnumConstants.isEmpty()) {
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
initializeEnumConstants(v);
public void generate(ExpressionCodegen codegen) {
initializeEnumConstants(codegen.v);
}
});
}
@@ -77,6 +77,8 @@ public class PropertyCodegen extends GenerationStateAware {
}
generateGetter(p, propertyDescriptor, p.getGetter());
generateSetter(p, propertyDescriptor, p.getSetter());
context.recordSyntheticAccessorIfNeeded(propertyDescriptor, typeMapper);
}
public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) {
@@ -131,7 +131,7 @@ public abstract class StackValue {
}
@NotNull
public static StackValue field(@NotNull Type type, @NotNull JvmClassName owner, @NotNull String name, boolean isStatic) {
public static Field field(@NotNull Type type, @NotNull JvmClassName owner, @NotNull String name, boolean isStatic) {
return new Field(type, owner, name, isStatic);
}
@@ -338,7 +338,7 @@ public abstract class StackValue {
return receiverWithParameter;
}
public static StackValue singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
public static Field singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
FieldInfo info = FieldInfo.createForSingleton(classDescriptor, typeMapper);
return field(info.getFieldType(), JvmClassName.byInternalName(info.getOwnerInternalName()), info.getFieldName(), true);
}
@@ -24,7 +24,8 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLOSURE;
public class ClassContext extends CodegenContext {
public class ClassContext extends CodegenContext<ClassDescriptor> {
public ClassContext(
@NotNull JetTypeMapper typeMapper,
@NotNull ClassDescriptor contextDescriptor,
@@ -38,6 +39,15 @@ public class ClassContext extends CodegenContext {
initOuterExpression(typeMapper, contextDescriptor);
}
@Nullable
public CodegenContext getClassObjectContext() {
if (getContextDescriptor().getClassObjectDescriptor() != null) {
return findChildContext(getContextDescriptor().getClassObjectDescriptor());
}
return null;
}
@Override
public boolean isStatic() {
return false;
@@ -27,21 +27,25 @@ 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.ConstructorDescriptorImpl;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.jetbrains.asm4.Opcodes.ACC_PRIVATE;
import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD;
import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
public abstract class CodegenContext {
public abstract class CodegenContext<T extends DeclarationDescriptor> {
public static final CodegenContext STATIC = new RootContext();
@NotNull
private final DeclarationDescriptor contextDescriptor;
private final T contextDescriptor;
@NotNull
private final OwnerKind contextKind;
@@ -52,13 +56,16 @@ public abstract class CodegenContext {
public final MutableClosure closure;
HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors;
private HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors;
private Map<DeclarationDescriptor, CodegenContext> childContexts;
protected StackValue outerExpression;
private final LocalLookup enclosingLocalLookup;
public CodegenContext(
@NotNull DeclarationDescriptor contextDescriptor,
@NotNull T contextDescriptor,
@NotNull OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable MutableClosure closure,
@@ -71,6 +78,10 @@ public abstract class CodegenContext {
this.closure = closure;
this.thisDescriptor = thisDescriptor;
this.enclosingLocalLookup = expressionCodegen;
if (parentContext != null) {
parentContext.addChild(this);
}
}
@NotNull
@@ -126,7 +137,7 @@ public abstract class CodegenContext {
}
@NotNull
public DeclarationDescriptor getContextDescriptor() {
public T getContextDescriptor() {
return contextDescriptor;
}
@@ -143,7 +154,7 @@ public abstract class CodegenContext {
return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo));
}
public CodegenContext 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);
}
@@ -297,4 +308,110 @@ public abstract class CodegenContext {
public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
}
@NotNull
public PropertyDescriptor accessablePropertyDescriptor(PropertyDescriptor propertyDescriptor) {
return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true);
}
@NotNull
public FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) {
return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true);
}
@NotNull
public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull JetTypeMapper typeMapper) {
if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, typeMapper)) {
accessibleDescriptorIfNeeded(fd, false);
}
}
@NotNull
public void recordSyntheticAccessorIfNeeded(PropertyDescriptor propertyDescriptor, JetTypeMapper typeMapper) {
if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) {
accessibleDescriptorIfNeeded(propertyDescriptor, false);
}
}
private boolean needSyntheticAccessorInBindingTrace(@NotNull CallableMemberDescriptor descriptor, @NotNull JetTypeMapper typeMapper) {
Boolean result = typeMapper.getBindingContext().get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor);
return result == null ? false : result.booleanValue();
}
@NotNull
private int getAccessFlags(CallableMemberDescriptor descriptor) {
int flag = getVisibilityAccessFlag(descriptor);
if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) |
(setter == null ? 0 : getVisibilityAccessFlag(setter));
}
return flag;
}
@NotNull
private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) {
int flag = getAccessFlags(descriptor);
if ((flag & ACC_PRIVATE) == 0) {
return descriptor;
}
CodegenContext descriptorContext = null;
if (!fromOutsideContext || getClassOrNamespaceDescriptor() != descriptor.getContainingDeclaration()) {
DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
boolean isClassObjectMember = DescriptorUtils.isClassObject(enclosed);
//go upper
if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) {
CodegenContext currentContext = this;
while (currentContext != null) {
if (currentContext.getContextDescriptor() == enclosed) {
descriptorContext = currentContext;
break;
}
//accessors for private members in class object for call from class
if (isClassObjectMember && currentContext instanceof ClassContext) {
ClassContext classContext = (ClassContext) currentContext;
CodegenContext classObject = classContext.getClassObjectContext();
if (classObject != null && classObject.getContextDescriptor() == enclosed) {
descriptorContext = classObject;
break;
}
}
currentContext = currentContext.getParentContext();
}
}
}
return (MemberDescriptor) (descriptorContext != null ? descriptorContext.getAccessor(descriptor) : descriptor);
}
private void addChild(@NotNull CodegenContext child) {
if (shouldAddChild(child)) {
if (childContexts == null) {
childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
}
DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
childContexts.put(childContextDescriptor, child);
}
}
protected boolean shouldAddChild(@NotNull CodegenContext child) {
DeclarationDescriptor childContextDescriptor = child.contextDescriptor;
if (childContextDescriptor instanceof ClassDescriptor) {
ClassKind kind = ((ClassDescriptor) childContextDescriptor).getKind();
return kind == ClassKind.CLASS_OBJECT;
}
return false;
}
@Nullable
public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
return childContexts == null ? null : childContexts.get(child);
}
}