Introducing class context stack

This commit is contained in:
Maxim Shafirov
2011-07-05 18:51:58 +04:00
parent 6bbf1a61fe
commit cde6d5765f
12 changed files with 315 additions and 205 deletions
@@ -20,12 +20,14 @@ public abstract class ClassBodyCodegen {
protected final OwnerKind kind; protected final OwnerKind kind;
protected final ClassDescriptor descriptor; protected final ClassDescriptor descriptor;
protected final ClassVisitor v; protected final ClassVisitor v;
protected final ClassContext context;
public ClassBodyCodegen(JetClassOrObject aClass, OwnerKind kind, ClassVisitor v, GenerationState state) { public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
this.state = state; this.state = state;
descriptor = state.getBindingContext().getClassDescriptor(aClass); descriptor = state.getBindingContext().getClassDescriptor(aClass);
myClass = aClass; myClass = aClass;
this.kind = kind; this.context = context;
this.kind = context.getContextKind();
this.v = v; this.v = v;
} }
@@ -45,8 +47,8 @@ public abstract class ClassBodyCodegen {
} }
private void generateClassBody() { private void generateClassBody() {
final FunctionCodegen functionCodegen = new FunctionCodegen((JetDeclaration) myClass, v, state); final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, functionCodegen, state); final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
for (JetDeclaration declaration : myClass.getDeclarations()) { for (JetDeclaration declaration : myClass.getDeclarations()) {
generateDeclaration(propertyCodegen, declaration, functionCodegen); generateDeclaration(propertyCodegen, declaration, functionCodegen);
@@ -57,25 +59,26 @@ public abstract class ClassBodyCodegen {
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, kind); propertyCodegen.gen((JetProperty) declaration);
} }
else if (declaration instanceof JetNamedFunction) { else if (declaration instanceof JetNamedFunction) {
try { try {
functionCodegen.gen((JetNamedFunction) declaration, kind); functionCodegen.gen((JetNamedFunction) declaration);
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw new RuntimeException("Error generating method " + myClass.getName() + "." + declaration.getName() + " in " + kind, e); throw new RuntimeException("Error generating method " + myClass.getName() + "." + declaration.getName() + " in " + context, e);
} }
} }
} }
private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen) { private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen) {
OwnerKind kind = context.getContextKind();
for (JetParameter p : getPrimaryConstructorParameters()) { for (JetParameter p : getPrimaryConstructorParameters()) {
if (p.getValOrVarNode() != null) { if (p.getValOrVarNode() != null) {
PropertyDescriptor propertyDescriptor = state.getBindingContext().getPropertyDescriptor(p); PropertyDescriptor propertyDescriptor = state.getBindingContext().getPropertyDescriptor(p);
if (propertyDescriptor != null) { if (propertyDescriptor != null) {
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
if (propertyDescriptor.isVar()) { if (propertyDescriptor.isVar()) {
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
} }
if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && state.getBindingContext().hasBackingField(propertyDescriptor)) { if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && state.getBindingContext().hasBackingField(propertyDescriptor)) {
@@ -16,36 +16,39 @@ public class ClassCodegen {
this.state = state; this.state = state;
} }
public void generate(JetClassOrObject aClass) { public void generate(ClassContext parentContext, JetClassOrObject aClass) {
state.prepareAnonymousClasses((JetElement) aClass); state.prepareAnonymousClasses((JetElement) aClass);
if (aClass instanceof JetObjectDeclaration) { if (aClass instanceof JetObjectDeclaration) {
generateImplementation(aClass, OwnerKind.IMPLEMENTATION); generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
} }
else { else {
generateInterface(aClass); generateInterface(parentContext, aClass);
generateImplementation(aClass, OwnerKind.IMPLEMENTATION); generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
generateImplementation(aClass, OwnerKind.DELEGATING_IMPLEMENTATION); generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
} }
ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION);
for (JetDeclaration declaration : aClass.getDeclarations()) { for (JetDeclaration declaration : aClass.getDeclarations()) {
if (declaration instanceof JetClass) { if (declaration instanceof JetClass) {
generate((JetClass) declaration); generate(contextForInners, (JetClass) declaration);
} }
} }
} }
private void generateInterface(JetClassOrObject aClass) { private void generateInterface(ClassContext parentContext, JetClassOrObject aClass) {
final ClassVisitor visitor = state.forClassInterface(state.getBindingContext().getClassDescriptor(aClass)); ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
new InterfaceBodyCodegen(aClass, visitor, state).generate(); final ClassVisitor visitor = state.forClassInterface(descriptor);
new InterfaceBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.INTERFACE), visitor, state).generate();
} }
private void generateImplementation(JetClassOrObject aClass, OwnerKind kind) { private void generateImplementation(ClassContext parentContext, JetClassOrObject aClass, OwnerKind kind) {
ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass); ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ClassVisitor v = kind == OwnerKind.IMPLEMENTATION
? state.forClassImplementation(descriptor) ? state.forClassImplementation(descriptor)
: state.forClassDelegatingImplementation(descriptor); : state.forClassDelegatingImplementation(descriptor);
new ImplementationBodyCodegen(aClass, kind, v, state).generate(); new ImplementationBodyCodegen(aClass, parentContext.intoClass(descriptor, kind), v, state).generate();
} }
@@ -3,18 +3,23 @@
*/ */
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.Type;
public class ClassContext { public class ClassContext {
public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null); public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null, null);
private final DeclarationDescriptor contextType; private final DeclarationDescriptor contextType;
private final OwnerKind contextKind; private final OwnerKind contextKind;
private final StackValue thisExpression; private final ClassContext parentContext;
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression) { public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext) {
this.contextType = contextType; this.contextType = contextType;
this.contextKind = contextKind; this.contextKind = contextKind;
this.thisExpression = thisExpression; this.parentContext = parentContext;
} }
public DeclarationDescriptor getContextType() { public DeclarationDescriptor getContextType() {
@@ -26,6 +31,82 @@ public class ClassContext {
} }
public StackValue getThisExpression() { public StackValue getThisExpression() {
return thisExpression; int thisIdx = -1;
if (getContextKind() != OwnerKind.NAMESPACE) {
thisIdx++;
}
if (hasReceiver()) {
thisIdx++;
}
if (thisIdx == -1) {
throw new RuntimeException("Has no this!" + contextType);
}
return StackValue.local(thisIdx, JetTypeMapper.TYPE_OBJECT);
}
public ClassContext intoNamespace(NamespaceDescriptor descriptor) {
return new ClassContext(descriptor, OwnerKind.NAMESPACE, null, this);
}
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind) {
final StackValue thisValue;
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
thisValue = StackValue.instanceField(JetTypeMapper.jetInterfaceType(descriptor),
JetTypeMapper.jetDelegatingImplementationType(descriptor).getInternalName(),
"$this");
}
else {
thisValue = StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
}
return new ClassContext(descriptor, kind, thisValue, this);
}
public ClassContext intoFunction(FunctionDescriptor descriptor) {
return new ClassContext(descriptor, getContextKind(), StackValue.local(0, JetTypeMapper.TYPE_OBJECT), this);
}
public ClassContext intoClosure() {
return new ClassContext(null, OwnerKind.IMPLEMENTATION, StackValue.local(0, JetTypeMapper.TYPE_OBJECT), this); // TODO!
}
public FrameMap prepareFrame() {
FrameMap frameMap = new FrameMap();
if (getContextKind() != OwnerKind.NAMESPACE) {
frameMap.enterTemp(); // 0 slot for this
}
if (hasReceiver()) {
frameMap.enterTemp(); // Next slot for fake this
}
return frameMap;
}
private JetType receiverType() {
return contextType instanceof FunctionDescriptor ? ((FunctionDescriptor) contextType).getReceiverType() : null;
}
private boolean hasReceiver() {
return receiverType() != null;
}
public ClassContext getParentContext() {
return parentContext;
}
public Type jvmType(JetTypeMapper mapper) {
if (contextType instanceof ClassDescriptor) {
if (contextKind == OwnerKind.INTERFACE) {
System.out.println("OOps?!");
}
return mapper.jvmType((ClassDescriptor) contextType, contextKind);
}
else {
return JetTypeMapper.TYPE_OBJECT; // TODO?
}
} }
} }
@@ -8,7 +8,8 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
@@ -25,15 +26,17 @@ import java.util.Map;
public class ClosureCodegen { public class ClosureCodegen {
private final GenerationState state; private final GenerationState state;
private final ExpressionCodegen context; private final ExpressionCodegen exprContext;
private final ClassContext context;
private ClassVisitor cv = null; private ClassVisitor cv = null;
private String name = null; private String name = null;
private Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>(); private Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
public ClosureCodegen(GenerationState state, ExpressionCodegen context) { public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, ClassContext context) {
this.state = state; this.state = state;
this.context = context; this.exprContext = exprContext;
this.context = context.intoClosure();
} }
public static Method erasedInvokeSignature(FunctionDescriptor fd) { public static Method erasedInvokeSignature(FunctionDescriptor fd) {
@@ -59,7 +62,7 @@ public class ClosureCodegen {
EnclosedValueDescriptor answer = closure.get(vd); EnclosedValueDescriptor answer = closure.get(vd);
if (answer != null) return answer.getInnerValue(); if (answer != null) return answer.getInnerValue();
final int idx = context.lookupLocal(vd); final int idx = exprContext.lookupLocal(vd);
if (idx < 0) return null; if (idx < 0) return null;
final Type type = state.getTypeMapper().mapType(vd.getOutType()); final Type type = state.getTypeMapper().mapType(vd.getOutType());
@@ -107,7 +110,7 @@ public class ClosureCodegen {
generateBridge(name, funDescriptor, cv); generateBridge(name, funDescriptor, cv);
generateBody(funDescriptor, cv, fun.getFunctionLiteral().getBodyExpression().getStatements()); generateBody(funDescriptor, cv, fun.getFunctionLiteral());
final Method constructor = generateConstructor(funClass); final Method constructor = generateConstructor(funClass);
@@ -121,10 +124,9 @@ public class ClosureCodegen {
return answer; return answer;
} }
private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, List<JetElement> body) { private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) {
FunctionCodegen fc = new FunctionCodegen(null, cv, state); FunctionCodegen fc = new FunctionCodegen(context, cv, state);
fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(), fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
funDescriptor.getValueParameters(), funDescriptor.getTypeParameters(), null);
} }
private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) { private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) {
@@ -5,6 +5,7 @@ import com.intellij.psi.*;
import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import gnu.trove.THashSet;
import jet.IntRange; import jet.IntRange;
import jet.JetObject; import jet.JetObject;
import jet.Range; import jet.Range;
@@ -79,7 +80,6 @@ public class ExpressionCodegen extends JetVisitor {
private final GenerationState state; private final GenerationState state;
private final Type returnType; private final Type returnType;
private final BindingContext bindingContext; private final BindingContext bindingContext;
private final Map<ClassDescriptor, StackValue> outerThisExpressions = new HashMap<ClassDescriptor, StackValue>();
private final Map<TypeParameterDescriptor, StackValue> typeParameterExpressions = new HashMap<TypeParameterDescriptor, StackValue>(); private final Map<TypeParameterDescriptor, StackValue> typeParameterExpressions = new HashMap<TypeParameterDescriptor, StackValue>();
private final ClassContext context; private final ClassContext context;
@@ -97,10 +97,6 @@ public class ExpressionCodegen extends JetVisitor {
this.context = context; this.context = context;
} }
public void addOuterThis(ClassDescriptor outer, StackValue expression) {
outerThisExpressions.put(outer, expression);
}
public void addTypeParameter(TypeParameterDescriptor typeParameter, StackValue expression) { public void addTypeParameter(TypeParameterDescriptor typeParameter, StackValue expression) {
typeParameterExpressions.put(typeParameter, expression); typeParameterExpressions.put(typeParameter, expression);
} }
@@ -315,7 +311,12 @@ public class ExpressionCodegen extends JetVisitor {
} }
private DeclarationDescriptor contextType() { private DeclarationDescriptor contextType() {
return context.getContextType(); DeclarationDescriptor descriptor = context.getContextType();
while (descriptor != null) {
if (descriptor instanceof ClassDescriptor || descriptor instanceof NamespaceDescriptor) return descriptor;
descriptor = descriptor.getContainingDeclaration();
}
return descriptor;
} }
private OwnerKind contextKind() { private OwnerKind contextKind() {
@@ -505,7 +506,7 @@ public class ExpressionCodegen extends JetVisitor {
generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements()); generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
} }
else { else {
final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this); final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this, context);
v.anew(Type.getObjectType(closure.getClassname())); v.anew(Type.getObjectType(closure.getClassname()));
v.dup(); v.dup();
@@ -523,7 +524,7 @@ public class ExpressionCodegen extends JetVisitor {
@Override @Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
GeneratedAnonymousClassDescriptor descriptor = state.generateObjectLiteral(expression, this); GeneratedAnonymousClassDescriptor descriptor = state.generateObjectLiteral(expression, this, context);
v.anew(Type.getObjectType(descriptor.getClassname())); v.anew(Type.getObjectType(descriptor.getClassname()));
v.dup(); v.dup();
v.invokespecial(descriptor.getClassname(), "<init>", descriptor.getConstructor().getDescriptor()); v.invokespecial(descriptor.getClassname(), "<init>", descriptor.getConstructor().getDescriptor());
@@ -885,30 +886,69 @@ public class ExpressionCodegen extends JetVisitor {
} }
} }
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) { else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) {
final StackValue value = generateThisOrOuter(calleeContainingClass); generateThisOrOuter(calleeContainingClass);
value.put(value.type, v);
} }
} }
public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) { private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) {
final StackValue value = outerThisExpressions.get(calleeContainingClass); Set<JetType> allSuperTypes = new THashSet<JetType>();
if (value != null) {
return value; addSuperTypes(subClass.getDefaultType(), allSuperTypes);
final DeclarationDescriptor superOriginal = superClass.getOriginal();
for (JetType superType : allSuperTypes) {
final DeclarationDescriptor descriptor = superType.getConstructor().getDeclarationDescriptor();
if (descriptor != null && superOriginal == descriptor.getOriginal()) {
return true;
}
} }
else {
// TODO hope it works; really need more checks here :) return false;
if (calleeContainingClass != null && contextType() instanceof ClassDescriptor && }
calleeContainingClass == contextType().getContainingDeclaration()) {
v.load(0, JetTypeMapper.TYPE_OBJECT); private static void addSuperTypes(JetType type, Set<JetType> set) {
return StackValue.field(typeMapper.jvmType(calleeContainingClass, OwnerKind.IMPLEMENTATION), set.add(type);
typeMapper.jvmName((ClassDescriptor) contextType(), OwnerKind.IMPLEMENTATION),
"this$0", for (JetType jetType : type.getConstructor().getSupertypes()) {
false); addSuperTypes(jetType, set);
// TODO handle more levels of class nestng }
} }
else {
return thisExpression() != null ? thisExpression() : StackValue.local(0, JetTypeMapper.TYPE_OBJECT); public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
boolean thisDone = false;
ClassContext cur = context;
while (true) {
ClassContext parentContext = cur.getParentContext();
if (parentContext == null) break;
final DeclarationDescriptor curContextType = cur.getContextType();
if (curContextType instanceof ClassDescriptor) {
if (isSubclass((ClassDescriptor) curContextType, calleeContainingClass)) break;
final StackValue outer;
if (!thisDone && myMap instanceof ConstructorFrameMap) {
outer = StackValue.local(((ConstructorFrameMap) myMap).getOuterThisIndex(), JetTypeMapper.TYPE_OBJECT);
}
else {
thisToStack();
outer = StackValue.field(parentContext.jvmType(typeMapper),
cur.jvmType(typeMapper).getInternalName(),
"this$0",
false);
}
thisDone = true;
outer.put(outer.type, v);
} }
cur = parentContext;
}
if (!thisDone) {
thisToStack();
} }
} }
@@ -1492,7 +1532,8 @@ public class ExpressionCodegen extends JetVisitor {
public void visitThisExpression(JetThisExpression expression) { public void visitThisExpression(JetThisExpression expression) {
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference()); final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference());
if (descriptor instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor) {
myStack.push(generateThisOrOuter((ClassDescriptor) descriptor)); generateThisOrOuter((ClassDescriptor) descriptor);
myStack.push(StackValue.onStack(JetTypeMapper.TYPE_OBJECT));
} }
else { else {
generateThis(); generateThis();
@@ -1505,27 +1546,7 @@ public class ExpressionCodegen extends JetVisitor {
} }
private void generateThis() { private void generateThis() {
if (thisExpression() != null) { myStack.push(thisExpression());
myStack.push(thisExpression());
return;
}
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);
myStack.push(StackValue.field(JetTypeMapper.jetInterfaceType(contextClass),
thisType.getInternalName(),
"$this",
false));
return;
}
}
throw new UnsupportedOperationException("'this' expression is not defined in the context");
} }
@Override @Override
@@ -1,12 +1,9 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@@ -22,49 +19,40 @@ import java.util.List;
* @author yole * @author yole
*/ */
public class FunctionCodegen { public class FunctionCodegen {
private final JetDeclaration owner; private final ClassContext owner;
private final ClassVisitor v; private final ClassVisitor v;
private final GenerationState state; private final GenerationState state;
public FunctionCodegen(JetDeclaration owner, ClassVisitor v, GenerationState state) { public FunctionCodegen(ClassContext owner, ClassVisitor v, GenerationState state) {
this.owner = owner; this.owner = owner;
this.v = v; this.v = v;
this.state = state; this.state = state;
} }
public void gen(JetNamedFunction f, OwnerKind kind) { public void gen(JetNamedFunction f) {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : state.getBindingContext().resolveTypeReference(receiverTypeRef);
Method method = state.getTypeMapper().mapToCallableMethod(f).getSignature(); Method method = state.getTypeMapper().mapToCallableMethod(f).getSignature();
final FunctionDescriptor functionDescriptor = state.getBindingContext().getFunctionDescriptor(f); final FunctionDescriptor functionDescriptor = state.getBindingContext().getFunctionDescriptor(f);
generateMethod(f, kind, method, receiverType, functionDescriptor.getValueParameters(), generateMethod(f, method, functionDescriptor);
functionDescriptor.getTypeParameters());
} }
public void generateMethod(JetDeclarationWithBody f, public void generateMethod(JetDeclarationWithBody f, Method jvmMethod, FunctionDescriptor functionDescriptor) {
OwnerKind kind, ClassContext funContext = owner.intoFunction(functionDescriptor);
Method jvmSignature,
@Nullable JetType receiverType,
List<ValueParameterDescriptor> paramDescrs,
List<TypeParameterDescriptor> typeParameters) {
final DeclarationDescriptor contextDesc = owner instanceof JetClassOrObject
? state.getBindingContext().getClassDescriptor((JetClassOrObject) owner)
: state.getBindingContext().getNamespaceDescriptor((JetNamespace) owner);
final JetExpression bodyExpression = f.getBodyExpression(); final JetExpression bodyExpression = f.getBodyExpression();
final List<JetElement> bodyExpressions = bodyExpression != null ? Collections.<JetElement>singletonList(bodyExpression) : null; final List<JetElement> bodyExpressions = bodyExpression != null ? Collections.<JetElement>singletonList(bodyExpression) : null;
generatedMethod(bodyExpressions, kind, jvmSignature, receiverType, paramDescrs, typeParameters, contextDesc); generatedMethod(bodyExpressions, jvmMethod, funContext, functionDescriptor.getValueParameters(), functionDescriptor.getTypeParameters());
} }
public void generatedMethod(List<JetElement> bodyExpressions, private void generatedMethod(List<JetElement> bodyExpressions,
OwnerKind kind, Method jvmSignature,
Method jvmSignature, ClassContext context,
JetType receiverType, List<ValueParameterDescriptor> paramDescrs,
List<ValueParameterDescriptor> paramDescrs, List<TypeParameterDescriptor> typeParameters)
List<TypeParameterDescriptor> typeParameters,
DeclarationDescriptor contextDesc)
{ {
int flags = Opcodes.ACC_PUBLIC; // TODO. int flags = Opcodes.ACC_PUBLIC; // TODO.
OwnerKind kind = context.getContextKind();
boolean isStatic = kind == OwnerKind.NAMESPACE; boolean isStatic = kind == OwnerKind.NAMESPACE;
if (isStatic) flags |= Opcodes.ACC_STATIC; if (isStatic) flags |= Opcodes.ACC_STATIC;
@@ -78,34 +66,19 @@ public class FunctionCodegen {
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
if (kind != OwnerKind.INTERFACE) { if (kind != OwnerKind.INTERFACE) {
mv.visitCode(); mv.visitCode();
FrameMap frameMap = new FrameMap(); FrameMap frameMap = context.prepareFrame();
int thisIdx = -1;
if (kind != OwnerKind.NAMESPACE) {
frameMap.enterTemp(); // 0 slot for this
thisIdx++;
}
if (receiverType != null) {
thisIdx++;
frameMap.enterTemp(); // Next slot for fake this
}
StackValue thisExpression = receiverType == null ? null : StackValue.local(thisIdx, state.getTypeMapper().mapType(receiverType));
ClassContext context = new ClassContext(contextDesc, kind, thisExpression);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
int firstArg = thisIdx+1;
Type[] argTypes = jvmSignature.getArgumentTypes(); Type[] argTypes = jvmSignature.getArgumentTypes();
for (int i = 0; i < paramDescrs.size(); i++) { for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i); ValueParameterDescriptor parameter = paramDescrs.get(i);
frameMap.enter(parameter, argTypes[i].getSize()); frameMap.enter(parameter, argTypes[i].getSize());
} }
for (int i = 0; i < typeParameters.size(); i++) {
final TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i); for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
codegen.addTypeParameter(typeParameterDescriptor, int slot = frameMap.enterTemp();
StackValue.local(firstArg + paramDescrs.size() + i, JetTypeMapper.TYPE_TYPEINFO)); codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
frameMap.enterTemp();
} }
if (kind instanceof OwnerKind.DelegateKind) { if (kind instanceof OwnerKind.DelegateKind) {
@@ -94,8 +94,8 @@ public class GenerationState {
} }
} }
public GeneratedAnonymousClassDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context) { public GeneratedAnonymousClassDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
final ClosureCodegen codegen = new ClosureCodegen(this, context); final ClosureCodegen codegen = new ClosureCodegen(this, context, classContext);
closureContexts.push(codegen); closureContexts.push(codegen);
try { try {
return codegen.gen(literal); return codegen.gen(literal);
@@ -106,9 +106,12 @@ public class GenerationState {
} }
} }
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context) { public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration()); Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration());
new ImplementationBodyCodegen(literal.getObjectDeclaration(), OwnerKind.IMPLEMENTATION, nameAndVisitor.getSecond(), this).generate();
final ClassContext objectContext = classContext.intoClass(getBindingContext().getClassDescriptor(literal.getObjectDeclaration()), OwnerKind.IMPLEMENTATION);
new ImplementationBodyCodegen(literal.getObjectDeclaration(), objectContext, nameAndVisitor.getSecond(), this).generate();
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("<init>", "()V")); return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("<init>", "()V"));
} }
@@ -20,8 +20,8 @@ import java.util.*;
* @author yole * @author yole
*/ */
public class ImplementationBodyCodegen extends ClassBodyCodegen { public class ImplementationBodyCodegen extends ClassBodyCodegen {
public ImplementationBodyCodegen(JetClassOrObject aClass, OwnerKind kind, ClassVisitor v, GenerationState state) { public ImplementationBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
super(aClass, kind, v, state); super(aClass, context, v, state);
} }
@Override @Override
@@ -112,7 +112,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, kind); ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, kind);
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
ClassContext context = new ClassContext(descriptor, kind, StackValue.local(0, state.getTypeMapper().jvmType(descriptor, kind)));
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
String classname = state.getTypeMapper().jvmName(descriptor, kind); String classname = state.getTypeMapper().jvmName(descriptor, kind);
@@ -138,7 +137,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
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(frameMap.getOuterThisIndex(), 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);
@@ -189,9 +187,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.putfield(classname, delegateField, fieldDesc); iv.putfield(classname, delegateField, fieldDesc);
JetClass superClass = (JetClass) state.getBindingContext().getDeclarationPsiElement(superClassDescriptor); JetClass superClass = (JetClass) state.getBindingContext().getDeclarationPsiElement(superClassDescriptor);
generateDelegates(myClass, superClass, final ClassContext delegateContext = context.intoClass(superClassDescriptor,
new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false), new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false),
JetTypeMapper.jvmNameForInterface(superClassDescriptor)), overridden); JetTypeMapper.jvmNameForInterface(superClassDescriptor)));
generateDelegates(superClass, delegateContext, overridden);
} }
n++; n++;
@@ -291,7 +290,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, kind); ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, kind);
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
ClassContext context = new ClassContext(descriptor, kind, StackValue.local(0, state.getTypeMapper().jvmType(descriptor, kind)));
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
for (JetDelegationSpecifier initializer : constructor.getInitializers()) { for (JetDelegationSpecifier initializer : constructor.getInitializers()) {
@@ -358,17 +356,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
protected void generateDelegates(JetClassOrObject inClass, JetClass toClass, OwnerKind kind, Set<FunctionDescriptor> overriden) { protected void generateDelegates(JetClass toClass, ClassContext delegateContext, Set<FunctionDescriptor> overriden) {
final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, state); final FunctionCodegen functionCodegen = new FunctionCodegen(delegateContext, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, functionCodegen, state); final PropertyCodegen propertyCodegen = new PropertyCodegen(delegateContext, v, functionCodegen, state);
for (JetDeclaration declaration : toClass.getDeclarations()) { for (JetDeclaration declaration : toClass.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, kind); propertyCodegen.gen((JetProperty) declaration);
} }
else if (declaration instanceof JetFunction) { else if (declaration instanceof JetFunction) {
if (!overriden.contains(state.getBindingContext().getFunctionDescriptor((JetNamedFunction) declaration))) { if (!overriden.contains(state.getBindingContext().getFunctionDescriptor((JetNamedFunction) declaration))) {
functionCodegen.gen((JetNamedFunction) declaration, kind); functionCodegen.gen((JetNamedFunction) declaration);
} }
} }
} }
@@ -377,9 +375,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (p.getValOrVarNode() != null) { if (p.getValOrVarNode() != null) {
PropertyDescriptor propertyDescriptor = state.getBindingContext().getPropertyDescriptor(p); PropertyDescriptor propertyDescriptor = state.getBindingContext().getPropertyDescriptor(p);
if (propertyDescriptor != null) { if (propertyDescriptor != null) {
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
if (propertyDescriptor.isVar()) { if (propertyDescriptor.isVar()) {
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
} }
} }
} }
@@ -17,8 +17,9 @@ import java.util.Set;
* @author yole * @author yole
*/ */
public class InterfaceBodyCodegen extends ClassBodyCodegen { public class InterfaceBodyCodegen extends ClassBodyCodegen {
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassVisitor v, GenerationState state) { public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
super(aClass, OwnerKind.INTERFACE, v, state); super(aClass, context, v, state);
assert context.getContextKind() == OwnerKind.INTERFACE;
} }
protected void generateDeclaration() { protected void generateDeclaration() {
@@ -33,8 +33,10 @@ public class NamespaceCodegen {
} }
public void generate(JetNamespace namespace) { public void generate(JetNamespace namespace) {
final FunctionCodegen functionCodegen = new FunctionCodegen(namespace, v, state); final ClassContext context = ClassContext.STATIC.intoNamespace(state.getBindingContext().getNamespaceDescriptor(namespace));
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, functionCodegen, state);
final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
final ClassCodegen classCodegen = state.forClass(); final ClassCodegen classCodegen = state.forClass();
state.prepareAnonymousClasses(namespace); state.prepareAnonymousClasses(namespace);
@@ -45,17 +47,17 @@ public class NamespaceCodegen {
for (JetDeclaration declaration : namespace.getDeclarations()) { for (JetDeclaration declaration : namespace.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, OwnerKind.NAMESPACE); propertyCodegen.gen((JetProperty) declaration);
} }
else if (declaration instanceof JetNamedFunction) { else if (declaration instanceof JetNamedFunction) {
try { try {
functionCodegen.gen((JetNamedFunction) declaration, OwnerKind.NAMESPACE); functionCodegen.gen((JetNamedFunction) declaration);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Failed to generate function " + declaration.getName(), e); throw new RuntimeException("Failed to generate function " + declaration.getName(), e);
} }
} }
else if (declaration instanceof JetClassOrObject) { else if (declaration instanceof JetClassOrObject) {
classCodegen.generate((JetClassOrObject) declaration); classCodegen.generate(context, (JetClassOrObject) declaration);
} }
else if (declaration instanceof JetNamespace) { else if (declaration instanceof JetNamespace) {
JetNamespace childNamespace = (JetNamespace) declaration; JetNamespace childNamespace = (JetNamespace) declaration;
@@ -1,9 +1,10 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
@@ -11,36 +12,32 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
import java.util.Collections;
/** /**
* @author max * @author max
*/ */
public class PropertyCodegen { public class PropertyCodegen {
private final GenerationState state; private final GenerationState state;
private final BindingContext context;
private final FunctionCodegen functionCodegen; private final FunctionCodegen functionCodegen;
private final ClassVisitor v; private final ClassVisitor v;
private final JetTypeMapper mapper; private final OwnerKind kind;
public PropertyCodegen(ClassVisitor v, FunctionCodegen functionCodegen, GenerationState state) { public PropertyCodegen(ClassContext context, ClassVisitor v, FunctionCodegen functionCodegen, GenerationState state) {
this.v = v; this.v = v;
this.functionCodegen = functionCodegen; this.functionCodegen = functionCodegen;
this.state = state; this.state = state;
mapper = state.getTypeMapper(); this.kind = context.getContextKind();
context = state.getBindingContext();
} }
public void gen(JetProperty p, OwnerKind kind) { public void gen(JetProperty p) {
final VariableDescriptor descriptor = context.getVariableDescriptor(p); final VariableDescriptor descriptor = state.getBindingContext().getVariableDescriptor(p);
if (!(descriptor instanceof PropertyDescriptor)) { if (!(descriptor instanceof PropertyDescriptor)) {
throw new UnsupportedOperationException("expect a property to have a property descriptor"); throw new UnsupportedOperationException("expect a property to have a property descriptor");
} }
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DELEGATING_IMPLEMENTATION) { if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
generateBackingField(p, kind, propertyDescriptor); generateBackingField(p, propertyDescriptor);
generateGetter(p, kind, propertyDescriptor); generateGetter(p, propertyDescriptor);
generateSetter(p, kind, propertyDescriptor); generateSetter(p, propertyDescriptor);
} }
else if (kind == OwnerKind.INTERFACE) { else if (kind == OwnerKind.INTERFACE) {
final JetPropertyAccessor getter = p.getGetter(); final JetPropertyAccessor getter = p.getGetter();
@@ -48,7 +45,7 @@ public class PropertyCodegen {
(getter == null && isExternallyAccessible(p)))) { (getter == null && isExternallyAccessible(p)))) {
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC, v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
getterName(p.getName()), getterName(p.getName()),
mapper.mapGetterSignature(propertyDescriptor).getDescriptor(), state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor(),
null, null); null, null);
} }
final JetPropertyAccessor setter = p.getSetter(); final JetPropertyAccessor setter = p.getSetter();
@@ -56,20 +53,20 @@ public class PropertyCodegen {
(setter == null && isExternallyAccessible(p) && p.isVar()))) { (setter == null && isExternallyAccessible(p) && p.isVar()))) {
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC, v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
setterName(p.getName()), setterName(p.getName()),
mapper.mapSetterSignature(propertyDescriptor).getDescriptor(), state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor(),
null, null); null, null);
} }
} }
else if (kind instanceof OwnerKind.DelegateKind) { else if (kind instanceof OwnerKind.DelegateKind) {
generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
if (propertyDescriptor.isVar()) { if (propertyDescriptor.isVar()) {
generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
} }
} }
} }
private void generateBackingField(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) { private void generateBackingField(JetProperty p, PropertyDescriptor propertyDescriptor) {
if (context.hasBackingField(propertyDescriptor)) { if (state.getBindingContext().hasBackingField(propertyDescriptor)) {
Object value = null; Object value = null;
final JetExpression initializer = p.getInitializer(); final JetExpression initializer = p.getInitializer();
if (initializer != null) { if (initializer != null) {
@@ -85,25 +82,22 @@ public class PropertyCodegen {
else { else {
modifiers = Opcodes.ACC_PRIVATE; modifiers = Opcodes.ACC_PRIVATE;
} }
v.visitField(modifiers, p.getName(), mapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value); v.visitField(modifiers, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value);
} }
} }
private void generateGetter(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) { private void generateGetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
final JetPropertyAccessor getter = p.getGetter(); final JetPropertyAccessor getter = p.getGetter();
if (getter != null) { if (getter != null) {
if (getter.getBodyExpression() != null) { if (getter.getBodyExpression() != null) {
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor), functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor), propertyDescriptor.getGetter());
null,
Collections.<ValueParameterDescriptor>emptyList(),
Collections.<TypeParameterDescriptor>emptyList());
} }
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) { else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultGetter(p, getter, kind); generateDefaultGetter(p, getter);
} }
} }
else if (isExternallyAccessible(p)) { else if (isExternallyAccessible(p)) {
generateDefaultGetter(p, p, kind); generateDefaultGetter(p, p);
} }
} }
@@ -111,33 +105,30 @@ public class PropertyCodegen {
return !p.hasModifier(JetTokens.PRIVATE_KEYWORD); return !p.hasModifier(JetTokens.PRIVATE_KEYWORD);
} }
private void generateSetter(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) { private void generateSetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
final JetPropertyAccessor setter = p.getSetter(); final JetPropertyAccessor setter = p.getSetter();
if (setter != null) { if (setter != null) {
if (setter.getBodyExpression() != null) { if (setter.getBodyExpression() != null) {
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
assert setterDescriptor != null; assert setterDescriptor != null;
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor), functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor), setterDescriptor);
null,
setterDescriptor.getValueParameters(),
Collections.<TypeParameterDescriptor>emptyList());
} }
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) { else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultSetter(p, setter, kind); generateDefaultSetter(p, setter);
} }
} }
else if (isExternallyAccessible(p) && p.isVar()) { else if (isExternallyAccessible(p) && p.isVar()) {
generateDefaultSetter(p, p, kind); generateDefaultSetter(p, p);
} }
} }
private void generateDefaultGetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) { private void generateDefaultGetter(JetProperty p, JetDeclaration declaration) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p); final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().getVariableDescriptor(p);
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC); int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
generateDefaultGetter(propertyDescriptor, flags, kind); generateDefaultGetter(propertyDescriptor, flags);
} }
public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags, OwnerKind kind) { public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags) {
if (kind == OwnerKind.NAMESPACE) { if (kind == OwnerKind.NAMESPACE) {
flags |= Opcodes.ACC_STATIC; flags |= Opcodes.ACC_STATIC;
} }
@@ -145,7 +136,7 @@ public class PropertyCodegen {
flags |= Opcodes.ACC_ABSTRACT; flags |= Opcodes.ACC_ABSTRACT;
} }
final String signature = mapper.mapGetterSignature(propertyDescriptor).getDescriptor(); final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor();
String getterName = getterName(propertyDescriptor.getName()); String getterName = getterName(propertyDescriptor.getName());
MethodVisitor mv = v.visitMethod(flags, getterName, signature, null, null); MethodVisitor mv = v.visitMethod(flags, getterName, signature, null, null);
if (kind != OwnerKind.INTERFACE) { if (kind != OwnerKind.INTERFACE) {
@@ -154,7 +145,7 @@ public class PropertyCodegen {
if (kind != OwnerKind.NAMESPACE) { if (kind != OwnerKind.NAMESPACE) {
iv.load(0, JetTypeMapper.TYPE_OBJECT); iv.load(0, JetTypeMapper.TYPE_OBJECT);
} }
final Type type = mapper.mapType(propertyDescriptor.getOutType()); final Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
if (kind instanceof OwnerKind.DelegateKind) { if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv); dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
@@ -162,7 +153,7 @@ public class PropertyCodegen {
} }
else { else {
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD, iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD,
mapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(), state.getTypeMapper().getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
type.getDescriptor()); type.getDescriptor());
} }
iv.areturn(type); iv.areturn(type);
@@ -171,13 +162,13 @@ public class PropertyCodegen {
} }
} }
private void generateDefaultSetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) { private void generateDefaultSetter(JetProperty p, JetDeclaration declaration) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p); final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().getVariableDescriptor(p);
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC); int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
generateDefaultSetter(propertyDescriptor, flags, kind); generateDefaultSetter(propertyDescriptor, flags);
} }
public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags, OwnerKind kind) { public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags) {
if (kind == OwnerKind.NAMESPACE) { if (kind == OwnerKind.NAMESPACE) {
flags |= Opcodes.ACC_STATIC; flags |= Opcodes.ACC_STATIC;
} }
@@ -185,12 +176,12 @@ public class PropertyCodegen {
flags |= Opcodes.ACC_ABSTRACT; flags |= Opcodes.ACC_ABSTRACT;
} }
final String signature = mapper.mapSetterSignature(propertyDescriptor).getDescriptor(); final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor();
MethodVisitor mv = v.visitMethod(flags, setterName(propertyDescriptor.getName()), signature, null, null); MethodVisitor mv = v.visitMethod(flags, setterName(propertyDescriptor.getName()), signature, null, null);
if (kind != OwnerKind.INTERFACE) { if (kind != OwnerKind.INTERFACE) {
mv.visitCode(); mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
final Type type = mapper.mapType(propertyDescriptor.getOutType()); final Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
int paramCode = 0; int paramCode = 0;
if (kind != OwnerKind.NAMESPACE) { if (kind != OwnerKind.NAMESPACE) {
iv.load(0, JetTypeMapper.TYPE_OBJECT); iv.load(0, JetTypeMapper.TYPE_OBJECT);
@@ -208,7 +199,7 @@ public class PropertyCodegen {
else { else {
iv.load(paramCode, type); iv.load(paramCode, type);
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD,
mapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(), state.getTypeMapper().getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
type.getDescriptor()); type.getDescriptor());
} }
@@ -71,6 +71,10 @@ public abstract class StackValue {
return new Field(type, owner, name, isStatic); return new Field(type, owner, name, isStatic);
} }
public static StackValue instanceField(Type type, String owner, String name) {
return new InstanceField(type, owner, name);
}
public static StackValue property(String name, String owner, Type type, boolean isStatic, boolean isInterface, Method getter, Method setter) { public static StackValue property(String name, String owner, Type type, boolean isStatic, boolean isInterface, Method getter, Method setter) {
return new Property(name, owner, getter, setter, isStatic, isInterface, type); return new Property(name, owner, getter, setter, isStatic, isInterface, type);
} }
@@ -379,6 +383,7 @@ public abstract class StackValue {
} }
} }
private static class Field extends StackValue { private static class Field extends StackValue {
private final String owner; private final String owner;
private final String name; private final String name;
@@ -414,6 +419,33 @@ public abstract class StackValue {
} }
} }
private static class InstanceField extends StackValue {
private final String owner;
private final String name;
public InstanceField(Type type, String owner, String name) {
super(type);
this.owner = owner;
this.name = name;
}
@Override
public void put(Type type, InstructionAdapter v) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.getfield(owner, name, this.type.getDescriptor());
}
@Override
public void dupReceiver(InstructionAdapter v, int below) {
}
@Override
public void store(InstructionAdapter v) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.putfield(owner, name, this.type.getDescriptor());
}
}
private static class Property extends StackValue { private static class Property extends StackValue {
private final String name; private final String name;
private final Method getter; private final Method getter;