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

This commit is contained in:
Dmitry Jemerov
2011-05-30 20:35:58 +04:00
parent e616c38a9f
commit 15f55d852d
6 changed files with 57 additions and 29 deletions
@@ -25,9 +25,7 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method; import org.objectweb.asm.commons.Method;
import java.util.Iterator; import java.util.*;
import java.util.List;
import java.util.Stack;
/** /**
* @author max * @author max
@@ -66,28 +64,33 @@ public class ExpressionCodegen extends JetVisitor {
private final InstructionAdapter v; private final InstructionAdapter v;
private final FrameMap myMap; private final FrameMap myMap;
private final JetTypeMapper typeMapper; private final JetTypeMapper typeMapper;
private final JetType receiverType;
private final Type returnType; private final Type returnType;
private final DeclarationDescriptor contextType; private final DeclarationDescriptor contextType;
private final OwnerKind contextKind; private final OwnerKind contextKind;
private final BindingContext bindingContext; private final BindingContext bindingContext;
private final StackValue thisExpression;
private final Map<ClassDescriptor, StackValue> outerThisExpressions = new HashMap<ClassDescriptor, StackValue>();
public ExpressionCodegen(MethodVisitor v, public ExpressionCodegen(MethodVisitor v,
BindingContext bindingContext, BindingContext bindingContext,
FrameMap myMap, FrameMap myMap,
JetTypeMapper typeMapper, JetTypeMapper typeMapper,
JetType receiverType,
Type returnType, Type returnType,
DeclarationDescriptor contextType, DeclarationDescriptor contextType,
OwnerKind contextKind) { OwnerKind contextKind,
@Nullable StackValue thisExpression) {
this.myMap = myMap; this.myMap = myMap;
this.typeMapper = typeMapper; this.typeMapper = typeMapper;
this.receiverType = receiverType;
this.returnType = returnType; this.returnType = returnType;
this.contextType = contextType; this.contextType = contextType;
this.contextKind = contextKind; this.contextKind = contextKind;
this.v = new InstructionAdapter(v); this.v = new InstructionAdapter(v);
this.bindingContext = bindingContext; this.bindingContext = bindingContext;
this.thisExpression = thisExpression;
}
public void addOuterThis(ClassDescriptor outer, StackValue expression) {
outerThisExpressions.put(outer, expression);
} }
static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) { static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) {
@@ -772,12 +775,18 @@ public class ExpressionCodegen extends JetVisitor {
} }
public void generateThisOrOuter(ClassDescriptor calleeContainingClass) { public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :) final StackValue value = outerThisExpressions.get(calleeContainingClass);
if (calleeContainingClass != null && contextType instanceof ClassDescriptor && if (value != null) {
calleeContainingClass == contextType.getContainingDeclaration()) { value.put(value.type, v);
v.getfield(typeMapper.jvmName((ClassDescriptor) contextType, OwnerKind.IMPLEMENTATION), }
"this$0", typeMapper.jvmType(calleeContainingClass, OwnerKind.IMPLEMENTATION).getDescriptor()); else {
// TODO handle more levels of class nestng 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() { private void generateThis() {
if (contextKind == OwnerKind.NAMESPACE) { if (thisExpression != null) {
if (receiverType != null) { myStack.push(thisExpression);
myStack.push(StackValue.local(0, typeMapper.mapType(receiverType))); return;
}
else {
throw new UnsupportedOperationException("Cannot generate this expression in top level context");
}
} }
else { if (contextKind == OwnerKind.NAMESPACE) {
ClassDescriptor contextClass = (ClassDescriptor) contextType; ClassDescriptor contextClass = (ClassDescriptor) contextType;
final Type thisType = typeMapper.jvmType(contextClass, contextKind); final Type thisType = typeMapper.jvmType(contextClass, contextKind);
if (contextKind == OwnerKind.IMPLEMENTATION) { if (contextKind == OwnerKind.IMPLEMENTATION) {
myStack.push(StackValue.local(0, thisType)); myStack.push(StackValue.local(0, thisType));
return;
} }
else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) { else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) {
v.load(0, thisType); v.load(0, thisType);
@@ -1438,11 +1444,10 @@ public class ExpressionCodegen extends JetVisitor {
thisType.getInternalName(), thisType.getInternalName(),
"$this", "$this",
false)); false));
} return;
else {
throw new UnsupportedOperationException("Unknown kind: " + contextKind);
} }
} }
throw new UnsupportedOperationException("'this' expression is not defined in the context");
} }
@Override @Override
@@ -77,8 +77,9 @@ public class FunctionCodegen {
frameMap.enter(parameter, argTypes[i].getSize()); frameMap.enter(parameter, argTypes[i].getSize());
} }
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, receiverType, StackValue thisExpression = receiverType == null ? null : StackValue.local(0, typeMapper.mapType(receiverType));
jvmSignature.getReturnType(), contextDescriptor, kind); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper,
jvmSignature.getReturnType(), contextDescriptor, kind, thisExpression);
if (kind instanceof OwnerKind.DelegateKind) { if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -87,7 +87,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
frameMap.enterTemp(); // this frameMap.enterTemp(); // this
final InstructionAdapter iv = new InstructionAdapter(mv); 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); String classname = typeMapper.jvmName(descriptor, kind);
final Type classType = Type.getType("L" + classname + ";"); final Type classType = Type.getType("L" + classname + ";");
@@ -108,11 +109,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V"); iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
} }
int index = 1; // this int index = 1; // 0 = this
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration(); final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
if (outerDescriptor instanceof ClassDescriptor) { if (outerDescriptor instanceof ClassDescriptor) {
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor; final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor); final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
codegen.addOuterThis(outerClassDescriptor, StackValue.local(1, type));
String interfaceDesc = type.getDescriptor(); String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0"; final String fieldName = "this$0";
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
@@ -75,7 +75,7 @@ public class NamespaceCodegen {
FrameMap frameMap = new FrameMap(); FrameMap frameMap = new FrameMap();
JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext); 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()) { for (JetDeclaration declaration : namespace.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
@@ -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"
}
@@ -87,4 +87,8 @@ public class ClassGenTest extends CodegenTestCase {
public void testInitializerBlockDImpl() throws Exception { public void testInitializerBlockDImpl() throws Exception {
blackBoxFile("classes/initializerBlockDImpl.jet"); blackBoxFile("classes/initializerBlockDImpl.jet");
} }
public void testPropertyInInitializer() throws Exception {
blackBoxFile("classes/propertyInInitializer.jet");
}
} }