KT-1136 proper generation of accessors

This commit is contained in:
Alex Tkachman
2012-01-25 13:29:16 +02:00
parent c9cba3e1cc
commit 4633e1c7f4
7 changed files with 144 additions and 90 deletions
@@ -40,19 +40,19 @@ public abstract class ClassBodyCodegen {
this.v = v; this.v = v;
} }
public final void generate(@Nullable HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors) { public final void generate() {
generateDeclaration(); generateDeclaration();
generateClassBody(); generateClassBody();
generateSyntheticParts(accessors); generateSyntheticParts();
generateStaticInitializer(); generateStaticInitializer();
} }
protected abstract void generateDeclaration(); protected abstract void generateDeclaration();
protected void generateSyntheticParts(HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors) { protected void generateSyntheticParts() {
} }
private void generateClassBody() { private void generateClassBody() {
@@ -51,11 +51,12 @@ public class ClassCodegen {
private void generateImplementation(CodegenContext context, JetClassOrObject aClass, OwnerKind kind, HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors, ClassBuilder classBuilder) { private void generateImplementation(CodegenContext context, JetClassOrObject aClass, OwnerKind kind, HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors, ClassBuilder classBuilder) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
CodegenContext classContext = context.intoClass(descriptor, kind, state.getTypeMapper()); CodegenContext classContext = context.intoClass(descriptor, kind, state.getTypeMapper());
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate(accessors); classContext.copyAccessors(accessors);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate();
if(aClass instanceof JetClass && ((JetClass)aClass).isTrait()) { if(aClass instanceof JetClass && ((JetClass)aClass).isTrait()) {
ClassBuilder traitBuilder = state.forTraitImplementation(descriptor); ClassBuilder traitBuilder = state.forTraitImplementation(descriptor);
new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state.getTypeMapper()), traitBuilder, state).generate(null); new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state.getTypeMapper()), traitBuilder, state).generate();
traitBuilder.done(); traitBuilder.done();
} }
} }
@@ -264,6 +264,15 @@ public abstract class CodegenContext {
public abstract boolean isStatic(); public abstract boolean isStatic();
public void copyAccessors(HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors) {
if(accessors != null) {
if(this.accessors == null) {
this.accessors = new HashMap<DeclarationDescriptor,DeclarationDescriptor>();
}
this.accessors.putAll(accessors);
}
}
public abstract static class ReceiverContext extends CodegenContext { public abstract static class ReceiverContext extends CodegenContext {
final CallableDescriptor receiverDescriptor; final CallableDescriptor receiverDescriptor;
@@ -145,7 +145,7 @@ public class GenerationState {
closure.name = nameAndVisitor.getFirst(); closure.name = nameAndVisitor.getFirst();
final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, typeMapper); final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, typeMapper);
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(null); new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate();
ConstructorDescriptor constructorDescriptor = closure.state.getBindingContext().get(BindingContext.CONSTRUCTOR, objectDeclaration); ConstructorDescriptor constructorDescriptor = closure.state.getBindingContext().get(BindingContext.CONSTRUCTOR, objectDeclaration);
CallableMethod callableMethod = closure.state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION); CallableMethod callableMethod = closure.state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION);
@@ -206,10 +206,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @Override
protected void generateSyntheticParts(HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors) { protected void generateSyntheticParts() {
generateFieldForObjectInstance(); generateFieldForObjectInstance();
generateFieldForClassObject(); generateFieldForClassObject();
generateAccessors(accessors);
try { try {
generatePrimaryConstructor(); generatePrimaryConstructor();
@@ -222,98 +221,104 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
generateGetTypeInfo(); generateGetTypeInfo();
generateAccessors();
} }
private void generateAccessors(HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors) { private void generateAccessors() {
if(accessors != null) { if(context.accessors != null) {
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) { for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : context.accessors.entrySet()) {
if(entry.getValue() instanceof FunctionDescriptor) { genAccessor(entry);
FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue(); }
FunctionDescriptor original = (FunctionDescriptor) entry.getKey(); }
}
Method method = typeMapper.mapSignature(bridge.getName(), bridge).getAsmMethod(); private void genAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) {
Method originalMethod = typeMapper.mapSignature(original.getName(), original).getAsmMethod(); if(entry.getValue() instanceof FunctionDescriptor) {
Type[] argTypes = method.getArgumentTypes(); FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue();
FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC|Opcodes.ACC_BRIDGE|Opcodes.ACC_FINAL, bridge.getName(), method.getDescriptor(), null, null); Method method = typeMapper.mapSignature(bridge.getName(), bridge).getAsmMethod();
if (v.generateCode()) { Method originalMethod = typeMapper.mapSignature(original.getName(), original).getAsmMethod();
mv.visitCode(); Type[] argTypes = method.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv); MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC|Opcodes.ACC_BRIDGE|Opcodes.ACC_FINAL, bridge.getName(), method.getDescriptor(), null, null);
if (v.generateCode()) {
mv.visitCode();
iv.load(0, JetTypeMapper.TYPE_OBJECT); InstructionAdapter iv = new InstructionAdapter(mv);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i]; iv.load(0, JetTypeMapper.TYPE_OBJECT);
iv.load(reg, argType); for (int i = 0, reg = 1; i < argTypes.length; i++) {
//noinspection AssignmentToForLoopParameter Type argType = argTypes[i];
reg += argType.getSize(); iv.load(reg, argType);
} //noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor());
iv.areturn(method.getReturnType());
FunctionCodegen.endVisit(iv, "accessor", null);
}
}
else if(entry.getValue() instanceof PropertyDescriptor) {
PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
{
Method method = typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod();
JvmPropertyAccessorSignature originalSignature = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION);
Method originalMethod = originalSignature.getJvmMethodSignature().getAsmMethod();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature.getPropertyTypeKotlinSignature(), originalSignature.getJvmMethodSignature().getKotlinTypeParameter());
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
if(original.getVisibility() == Visibility.PRIVATE)
iv.getfield(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), original.getName(), originalMethod.getReturnType().getDescriptor());
else
iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor()); iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor());
iv.areturn(method.getReturnType()); iv.areturn(method.getReturnType());
FunctionCodegen.endVisit(iv, "accessor", null); FunctionCodegen.endVisit(iv, "accessor", null);
}
}
else if(entry.getValue() instanceof PropertyDescriptor) {
PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
{
Method method = typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod();
JvmPropertyAccessorSignature originalSignature = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION);
Method originalMethod = originalSignature.getJvmMethodSignature().getAsmMethod();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature.getPropertyTypeKotlinSignature(), originalSignature.getJvmMethodSignature().getKotlinTypeParameter());
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
if(original.getVisibility() == Visibility.PRIVATE)
iv.getfield(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), original.getName(), originalMethod.getReturnType().getDescriptor());
else
iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor());
iv.areturn(method.getReturnType());
FunctionCodegen.endVisit(iv, "accessor", null);
}
}
{
Method method = typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod();
JvmPropertyAccessorSignature originalSignature2 = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION);
Method originalMethod = originalSignature2.getJvmMethodSignature().getAsmMethod();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature2.getPropertyTypeKotlinSignature(), originalSignature2.getJvmMethodSignature().getKotlinTypeParameter());
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
Type[] argTypes = method.getArgumentTypes();
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
if(original.getVisibility() == Visibility.PRIVATE)
iv.putfield(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), original.getName(), originalMethod.getArgumentTypes()[0].getDescriptor());
else
iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor());
iv.areturn(method.getReturnType());
FunctionCodegen.endVisit(iv, "accessor", null);
}
}
}
else {
throw new UnsupportedOperationException();
} }
} }
if(bridge.isVar())
{
Method method = typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod();
JvmPropertyAccessorSignature originalSignature2 = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION);
Method originalMethod = originalSignature2.getJvmMethodSignature().getAsmMethod();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature2.getPropertyTypeKotlinSignature(), originalSignature2.getJvmMethodSignature().getKotlinTypeParameter());
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
Type[] argTypes = method.getArgumentTypes();
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
if(original.getVisibility() == Visibility.PRIVATE)
iv.putfield(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), original.getName(), originalMethod.getArgumentTypes()[0].getDescriptor());
else
iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor());
iv.areturn(method.getReturnType());
FunctionCodegen.endVisit(iv, "accessor", null);
}
}
}
else {
throw new UnsupportedOperationException();
} }
} }
@@ -0,0 +1,35 @@
import java.util.ArrayList
public class SomeClass() {
class Inner {
val copy = list
}
private val list = ArrayList<String>()
var status : Throwable? = null
private val workerThread = object : Thread() {
public override fun run() {
try {
list.add("123")
list.add("33")
Inner().copy.add("444")
}
catch(t: Throwable) {
status = t
}
}
}
{
workerThread.start()
workerThread.join()
}
}
public fun box():String {
var obj = SomeClass()
return if(obj.status == null) "OK" else {
obj.status?.printStackTrace()
"failed"
}
}
@@ -30,4 +30,8 @@ public class ObjectGenTest extends CodegenTestCase {
public void testKt640() throws Exception { public void testKt640() throws Exception {
blackBoxFile("regressions/kt640.jet"); blackBoxFile("regressions/kt640.jet");
} }
public void testKt1136() throws Exception {
blackBoxFile("regressions/kt1136.kt");
}
} }