From 15f55d852d1a40ebf7a4af2cd64c799b8ef956f8 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 30 May 2011 20:35:58 +0400 Subject: [PATCH] first step of refactoring code to generate 'this' expressions and receivers in ExpressionCodegen; correctly generate references to outer class properties in inner superclass constructor call --- .../jet/codegen/ExpressionCodegen.java | 53 ++++++++++--------- .../jet/codegen/FunctionCodegen.java | 5 +- .../codegen/ImplementationBodyCodegen.java | 6 ++- .../jet/codegen/NamespaceCodegen.java | 2 +- .../codegen/classes/propertyInInitializer.jet | 16 ++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 4 ++ 6 files changed, 57 insertions(+), 29 deletions(-) create mode 100644 idea/testData/codegen/classes/propertyInInitializer.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index c63bb4288d4..dc827077875 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -25,9 +25,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; -import java.util.Iterator; -import java.util.List; -import java.util.Stack; +import java.util.*; /** * @author max @@ -66,28 +64,33 @@ public class ExpressionCodegen extends JetVisitor { private final InstructionAdapter v; private final FrameMap myMap; private final JetTypeMapper typeMapper; - private final JetType receiverType; private final Type returnType; private final DeclarationDescriptor contextType; private final OwnerKind contextKind; private final BindingContext bindingContext; + private final StackValue thisExpression; + private final Map outerThisExpressions = new HashMap(); public ExpressionCodegen(MethodVisitor v, BindingContext bindingContext, FrameMap myMap, JetTypeMapper typeMapper, - JetType receiverType, Type returnType, DeclarationDescriptor contextType, - OwnerKind contextKind) { + OwnerKind contextKind, + @Nullable StackValue thisExpression) { this.myMap = myMap; this.typeMapper = typeMapper; - this.receiverType = receiverType; this.returnType = returnType; this.contextType = contextType; this.contextKind = contextKind; this.v = new InstructionAdapter(v); this.bindingContext = bindingContext; + this.thisExpression = thisExpression; + } + + public void addOuterThis(ClassDescriptor outer, StackValue expression) { + outerThisExpressions.put(outer, expression); } static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) { @@ -772,12 +775,18 @@ public class ExpressionCodegen extends JetVisitor { } public void generateThisOrOuter(ClassDescriptor calleeContainingClass) { - v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :) - if (calleeContainingClass != null && contextType instanceof ClassDescriptor && - calleeContainingClass == contextType.getContainingDeclaration()) { - v.getfield(typeMapper.jvmName((ClassDescriptor) contextType, OwnerKind.IMPLEMENTATION), - "this$0", typeMapper.jvmType(calleeContainingClass, OwnerKind.IMPLEMENTATION).getDescriptor()); - // TODO handle more levels of class nestng + final StackValue value = outerThisExpressions.get(calleeContainingClass); + if (value != null) { + value.put(value.type, v); + } + else { + v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :) + if (calleeContainingClass != null && contextType instanceof ClassDescriptor && + calleeContainingClass == contextType.getContainingDeclaration()) { + v.getfield(typeMapper.jvmName((ClassDescriptor) contextType, OwnerKind.IMPLEMENTATION), + "this$0", typeMapper.jvmType(calleeContainingClass, OwnerKind.IMPLEMENTATION).getDescriptor()); + // TODO handle more levels of class nestng + } } } @@ -1418,19 +1427,16 @@ public class ExpressionCodegen extends JetVisitor { } private void generateThis() { - if (contextKind == OwnerKind.NAMESPACE) { - if (receiverType != null) { - myStack.push(StackValue.local(0, typeMapper.mapType(receiverType))); - } - else { - throw new UnsupportedOperationException("Cannot generate this expression in top level context"); - } + if (thisExpression != null) { + myStack.push(thisExpression); + return; } - else { + if (contextKind == OwnerKind.NAMESPACE) { ClassDescriptor contextClass = (ClassDescriptor) contextType; final Type thisType = typeMapper.jvmType(contextClass, contextKind); if (contextKind == OwnerKind.IMPLEMENTATION) { myStack.push(StackValue.local(0, thisType)); + return; } else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) { v.load(0, thisType); @@ -1438,11 +1444,10 @@ public class ExpressionCodegen extends JetVisitor { thisType.getInternalName(), "$this", false)); - } - else { - throw new UnsupportedOperationException("Unknown kind: " + contextKind); + return; } } + throw new UnsupportedOperationException("'this' expression is not defined in the context"); } @Override diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 9213904c1e9..5b6dbe8696a 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -77,8 +77,9 @@ public class FunctionCodegen { frameMap.enter(parameter, argTypes[i].getSize()); } - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, receiverType, - jvmSignature.getReturnType(), contextDescriptor, kind); + StackValue thisExpression = receiverType == null ? null : StackValue.local(0, typeMapper.mapType(receiverType)); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, + jvmSignature.getReturnType(), contextDescriptor, kind, thisExpression); if (kind instanceof OwnerKind.DelegateKind) { OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; InstructionAdapter iv = new InstructionAdapter(mv); diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 8e3216b8ea5..47fcc302105 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -87,7 +87,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { frameMap.enterTemp(); // this final InstructionAdapter iv = new InstructionAdapter(mv); - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, descriptor, kind); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, + descriptor, kind, StackValue.local(0, typeMapper.jvmType(descriptor, kind))); String classname = typeMapper.jvmName(descriptor, kind); final Type classType = Type.getType("L" + classname + ";"); @@ -108,11 +109,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.invokespecial(superClass, "", /* TODO super constructor descriptor */"()V"); } - int index = 1; // this + int index = 1; // 0 = this final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration(); if (outerDescriptor instanceof ClassDescriptor) { final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor; final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor); + codegen.addOuterThis(outerClassDescriptor, StackValue.local(1, type)); String interfaceDesc = type.getDescriptor(); final String fieldName = "this$0"; v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 90c14330be1..f8bbb64d0a5 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -75,7 +75,7 @@ public class NamespaceCodegen { FrameMap frameMap = new FrameMap(); JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext); - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, null, OwnerKind.NAMESPACE); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, null, OwnerKind.NAMESPACE, null); for (JetDeclaration declaration : namespace.getDeclarations()) { if (declaration instanceof JetProperty) { diff --git a/idea/testData/codegen/classes/propertyInInitializer.jet b/idea/testData/codegen/classes/propertyInInitializer.jet new file mode 100644 index 00000000000..8bf3d48ef54 --- /dev/null +++ b/idea/testData/codegen/classes/propertyInInitializer.jet @@ -0,0 +1,16 @@ +class Outer() { + public val s = "xyzzy" + + class InnerBase(public val name: String) { + } + + class InnerDerived(): InnerBase(s) { + } + + public val x = new InnerDerived() +} + +fun box() { + val o = new Outer() + return if (o.x.name != "xyzzy") "fail" else "OK" +} diff --git a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 5e9815416c3..281ab85eec5 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -87,4 +87,8 @@ public class ClassGenTest extends CodegenTestCase { public void testInitializerBlockDImpl() throws Exception { blackBoxFile("classes/initializerBlockDImpl.jet"); } + + public void testPropertyInInitializer() throws Exception { + blackBoxFile("classes/propertyInInitializer.jet"); + } }