KT-1136 proper generation of accessors
This commit is contained in:
@@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user