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 ClassDescriptor descriptor;
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;
descriptor = state.getBindingContext().getClassDescriptor(aClass);
myClass = aClass;
this.kind = kind;
this.context = context;
this.kind = context.getContextKind();
this.v = v;
}
@@ -45,8 +47,8 @@ public abstract class ClassBodyCodegen {
}
private void generateClassBody() {
final FunctionCodegen functionCodegen = new FunctionCodegen((JetDeclaration) myClass, v, state);
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);
for (JetDeclaration declaration : myClass.getDeclarations()) {
generateDeclaration(propertyCodegen, declaration, functionCodegen);
@@ -57,25 +59,26 @@ public abstract class ClassBodyCodegen {
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, kind);
propertyCodegen.gen((JetProperty) declaration);
}
else if (declaration instanceof JetNamedFunction) {
try {
functionCodegen.gen((JetNamedFunction) declaration, kind);
functionCodegen.gen((JetNamedFunction) declaration);
} 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) {
OwnerKind kind = context.getContextKind();
for (JetParameter p : getPrimaryConstructorParameters()) {
if (p.getValOrVarNode() != null) {
PropertyDescriptor propertyDescriptor = state.getBindingContext().getPropertyDescriptor(p);
if (propertyDescriptor != null) {
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
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)) {
@@ -16,36 +16,39 @@ public class ClassCodegen {
this.state = state;
}
public void generate(JetClassOrObject aClass) {
public void generate(ClassContext parentContext, JetClassOrObject aClass) {
state.prepareAnonymousClasses((JetElement) aClass);
if (aClass instanceof JetObjectDeclaration) {
generateImplementation(aClass, OwnerKind.IMPLEMENTATION);
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
}
else {
generateInterface(aClass);
generateImplementation(aClass, OwnerKind.IMPLEMENTATION);
generateImplementation(aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
generateInterface(parentContext, aClass);
generateImplementation(parentContext, aClass, OwnerKind.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()) {
if (declaration instanceof JetClass) {
generate((JetClass) declaration);
generate(contextForInners, (JetClass) declaration);
}
}
}
private void generateInterface(JetClassOrObject aClass) {
final ClassVisitor visitor = state.forClassInterface(state.getBindingContext().getClassDescriptor(aClass));
new InterfaceBodyCodegen(aClass, visitor, state).generate();
private void generateInterface(ClassContext parentContext, JetClassOrObject aClass) {
ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
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);
ClassVisitor v = kind == OwnerKind.IMPLEMENTATION
? state.forClassImplementation(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;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
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 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 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.contextKind = contextKind;
this.thisExpression = thisExpression;
this.parentContext = parentContext;
}
public DeclarationDescriptor getContextType() {
@@ -26,6 +31,82 @@ public class ClassContext {
}
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.ValueParameterDescriptor;
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.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -25,15 +26,17 @@ import java.util.Map;
public class ClosureCodegen {
private final GenerationState state;
private final ExpressionCodegen context;
private final ExpressionCodegen exprContext;
private final ClassContext context;
private ClassVisitor cv = null;
private String name = null;
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.context = context;
this.exprContext = exprContext;
this.context = context.intoClosure();
}
public static Method erasedInvokeSignature(FunctionDescriptor fd) {
@@ -59,7 +62,7 @@ public class ClosureCodegen {
EnclosedValueDescriptor answer = closure.get(vd);
if (answer != null) return answer.getInnerValue();
final int idx = context.lookupLocal(vd);
final int idx = exprContext.lookupLocal(vd);
if (idx < 0) return null;
final Type type = state.getTypeMapper().mapType(vd.getOutType());
@@ -107,7 +110,7 @@ public class ClosureCodegen {
generateBridge(name, funDescriptor, cv);
generateBody(funDescriptor, cv, fun.getFunctionLiteral().getBodyExpression().getStatements());
generateBody(funDescriptor, cv, fun.getFunctionLiteral());
final Method constructor = generateConstructor(funClass);
@@ -121,10 +124,9 @@ public class ClosureCodegen {
return answer;
}
private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, List<JetElement> body) {
FunctionCodegen fc = new FunctionCodegen(null, cv, state);
fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(),
funDescriptor.getValueParameters(), funDescriptor.getTypeParameters(), null);
private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) {
FunctionCodegen fc = new FunctionCodegen(context, cv, state);
fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
}
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.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import gnu.trove.THashSet;
import jet.IntRange;
import jet.JetObject;
import jet.Range;
@@ -79,7 +80,6 @@ public class ExpressionCodegen extends JetVisitor {
private final GenerationState state;
private final Type returnType;
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 ClassContext context;
@@ -97,10 +97,6 @@ public class ExpressionCodegen extends JetVisitor {
this.context = context;
}
public void addOuterThis(ClassDescriptor outer, StackValue expression) {
outerThisExpressions.put(outer, expression);
}
public void addTypeParameter(TypeParameterDescriptor typeParameter, StackValue expression) {
typeParameterExpressions.put(typeParameter, expression);
}
@@ -315,7 +311,12 @@ public class ExpressionCodegen extends JetVisitor {
}
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() {
@@ -505,7 +506,7 @@ public class ExpressionCodegen extends JetVisitor {
generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
}
else {
final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this);
final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this, context);
v.anew(Type.getObjectType(closure.getClassname()));
v.dup();
@@ -523,7 +524,7 @@ public class ExpressionCodegen extends JetVisitor {
@Override
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.dup();
v.invokespecial(descriptor.getClassname(), "<init>", descriptor.getConstructor().getDescriptor());
@@ -885,30 +886,69 @@ public class ExpressionCodegen extends JetVisitor {
}
}
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) {
final StackValue value = generateThisOrOuter(calleeContainingClass);
value.put(value.type, v);
generateThisOrOuter(calleeContainingClass);
}
}
public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) {
final StackValue value = outerThisExpressions.get(calleeContainingClass);
if (value != null) {
return value;
private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) {
Set<JetType> allSuperTypes = new THashSet<JetType>();
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 :)
if (calleeContainingClass != null && contextType() instanceof ClassDescriptor &&
calleeContainingClass == contextType().getContainingDeclaration()) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
return StackValue.field(typeMapper.jvmType(calleeContainingClass, OwnerKind.IMPLEMENTATION),
typeMapper.jvmName((ClassDescriptor) contextType(), OwnerKind.IMPLEMENTATION),
"this$0",
false);
// TODO handle more levels of class nestng
}
else {
return thisExpression() != null ? thisExpression() : StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
return false;
}
private static void addSuperTypes(JetType type, Set<JetType> set) {
set.add(type);
for (JetType jetType : type.getConstructor().getSupertypes()) {
addSuperTypes(jetType, set);
}
}
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) {
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference());
if (descriptor instanceof ClassDescriptor) {
myStack.push(generateThisOrOuter((ClassDescriptor) descriptor));
generateThisOrOuter((ClassDescriptor) descriptor);
myStack.push(StackValue.onStack(JetTypeMapper.TYPE_OBJECT));
}
else {
generateThis();
@@ -1505,27 +1546,7 @@ public class ExpressionCodegen extends JetVisitor {
}
private void generateThis() {
if (thisExpression() != null) {
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");
myStack.push(thisExpression());
}
@Override
@@ -1,12 +1,9 @@
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.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -22,49 +19,40 @@ import java.util.List;
* @author yole
*/
public class FunctionCodegen {
private final JetDeclaration owner;
private final ClassContext owner;
private final ClassVisitor v;
private final GenerationState state;
public FunctionCodegen(JetDeclaration owner, ClassVisitor v, GenerationState state) {
public FunctionCodegen(ClassContext owner, ClassVisitor v, GenerationState state) {
this.owner = owner;
this.v = v;
this.state = state;
}
public void gen(JetNamedFunction f, OwnerKind kind) {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : state.getBindingContext().resolveTypeReference(receiverTypeRef);
public void gen(JetNamedFunction f) {
Method method = state.getTypeMapper().mapToCallableMethod(f).getSignature();
final FunctionDescriptor functionDescriptor = state.getBindingContext().getFunctionDescriptor(f);
generateMethod(f, kind, method, receiverType, functionDescriptor.getValueParameters(),
functionDescriptor.getTypeParameters());
generateMethod(f, method, functionDescriptor);
}
public void generateMethod(JetDeclarationWithBody f,
OwnerKind kind,
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);
public void generateMethod(JetDeclarationWithBody f, Method jvmMethod, FunctionDescriptor functionDescriptor) {
ClassContext funContext = owner.intoFunction(functionDescriptor);
final JetExpression bodyExpression = f.getBodyExpression();
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,
OwnerKind kind,
Method jvmSignature,
JetType receiverType,
List<ValueParameterDescriptor> paramDescrs,
List<TypeParameterDescriptor> typeParameters,
DeclarationDescriptor contextDesc)
private void generatedMethod(List<JetElement> bodyExpressions,
Method jvmSignature,
ClassContext context,
List<ValueParameterDescriptor> paramDescrs,
List<TypeParameterDescriptor> typeParameters)
{
int flags = Opcodes.ACC_PUBLIC; // TODO.
OwnerKind kind = context.getContextKind();
boolean isStatic = kind == OwnerKind.NAMESPACE;
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);
if (kind != OwnerKind.INTERFACE) {
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);
int firstArg = thisIdx+1;
Type[] argTypes = jvmSignature.getArgumentTypes();
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
frameMap.enter(parameter, argTypes[i].getSize());
}
for (int i = 0; i < typeParameters.size(); i++) {
final TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
codegen.addTypeParameter(typeParameterDescriptor,
StackValue.local(firstArg + paramDescrs.size() + i, JetTypeMapper.TYPE_TYPEINFO));
frameMap.enterTemp();
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
int slot = frameMap.enterTemp();
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
}
if (kind instanceof OwnerKind.DelegateKind) {
@@ -94,8 +94,8 @@ public class GenerationState {
}
}
public GeneratedAnonymousClassDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context) {
final ClosureCodegen codegen = new ClosureCodegen(this, context);
public GeneratedAnonymousClassDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
final ClosureCodegen codegen = new ClosureCodegen(this, context, classContext);
closureContexts.push(codegen);
try {
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());
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"));
}
@@ -20,8 +20,8 @@ import java.util.*;
* @author yole
*/
public class ImplementationBodyCodegen extends ClassBodyCodegen {
public ImplementationBodyCodegen(JetClassOrObject aClass, OwnerKind kind, ClassVisitor v, GenerationState state) {
super(aClass, kind, v, state);
public ImplementationBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
super(aClass, context, v, state);
}
@Override
@@ -112,7 +112,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, kind);
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);
String classname = state.getTypeMapper().jvmName(descriptor, kind);
@@ -138,7 +137,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (outerDescriptor instanceof ClassDescriptor) {
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
codegen.addOuterThis(outerClassDescriptor, StackValue.local(frameMap.getOuterThisIndex(), type));
String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0";
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);
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),
JetTypeMapper.jvmNameForInterface(superClassDescriptor)), overridden);
JetTypeMapper.jvmNameForInterface(superClassDescriptor)));
generateDelegates(superClass, delegateContext, overridden);
}
n++;
@@ -291,7 +290,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, kind);
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);
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) {
final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, functionCodegen, state);
protected void generateDelegates(JetClass toClass, ClassContext delegateContext, Set<FunctionDescriptor> overriden) {
final FunctionCodegen functionCodegen = new FunctionCodegen(delegateContext, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(delegateContext, v, functionCodegen, state);
for (JetDeclaration declaration : toClass.getDeclarations()) {
if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, kind);
propertyCodegen.gen((JetProperty) declaration);
}
else if (declaration instanceof JetFunction) {
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) {
PropertyDescriptor propertyDescriptor = state.getBindingContext().getPropertyDescriptor(p);
if (propertyDescriptor != null) {
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
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
*/
public class InterfaceBodyCodegen extends ClassBodyCodegen {
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassVisitor v, GenerationState state) {
super(aClass, OwnerKind.INTERFACE, v, state);
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
super(aClass, context, v, state);
assert context.getContextKind() == OwnerKind.INTERFACE;
}
protected void generateDeclaration() {
@@ -33,8 +33,10 @@ public class NamespaceCodegen {
}
public void generate(JetNamespace namespace) {
final FunctionCodegen functionCodegen = new FunctionCodegen(namespace, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, functionCodegen, state);
final ClassContext context = ClassContext.STATIC.intoNamespace(state.getBindingContext().getNamespaceDescriptor(namespace));
final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
final ClassCodegen classCodegen = state.forClass();
state.prepareAnonymousClasses(namespace);
@@ -45,17 +47,17 @@ public class NamespaceCodegen {
for (JetDeclaration declaration : namespace.getDeclarations()) {
if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, OwnerKind.NAMESPACE);
propertyCodegen.gen((JetProperty) declaration);
}
else if (declaration instanceof JetNamedFunction) {
try {
functionCodegen.gen((JetNamedFunction) declaration, OwnerKind.NAMESPACE);
functionCodegen.gen((JetNamedFunction) declaration);
} catch (Exception e) {
throw new RuntimeException("Failed to generate function " + declaration.getName(), e);
}
}
else if (declaration instanceof JetClassOrObject) {
classCodegen.generate((JetClassOrObject) declaration);
classCodegen.generate(context, (JetClassOrObject) declaration);
}
else if (declaration instanceof JetNamespace) {
JetNamespace childNamespace = (JetNamespace) declaration;
@@ -1,9 +1,10 @@
package org.jetbrains.jet.codegen;
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.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetTokens;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
@@ -11,36 +12,32 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import java.util.Collections;
/**
* @author max
*/
public class PropertyCodegen {
private final GenerationState state;
private final BindingContext context;
private final FunctionCodegen functionCodegen;
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.functionCodegen = functionCodegen;
this.state = state;
mapper = state.getTypeMapper();
context = state.getBindingContext();
this.kind = context.getContextKind();
}
public void gen(JetProperty p, OwnerKind kind) {
final VariableDescriptor descriptor = context.getVariableDescriptor(p);
public void gen(JetProperty p) {
final VariableDescriptor descriptor = state.getBindingContext().getVariableDescriptor(p);
if (!(descriptor instanceof PropertyDescriptor)) {
throw new UnsupportedOperationException("expect a property to have a property descriptor");
}
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
generateBackingField(p, kind, propertyDescriptor);
generateGetter(p, kind, propertyDescriptor);
generateSetter(p, kind, propertyDescriptor);
generateBackingField(p, propertyDescriptor);
generateGetter(p, propertyDescriptor);
generateSetter(p, propertyDescriptor);
}
else if (kind == OwnerKind.INTERFACE) {
final JetPropertyAccessor getter = p.getGetter();
@@ -48,7 +45,7 @@ public class PropertyCodegen {
(getter == null && isExternallyAccessible(p)))) {
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
getterName(p.getName()),
mapper.mapGetterSignature(propertyDescriptor).getDescriptor(),
state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor(),
null, null);
}
final JetPropertyAccessor setter = p.getSetter();
@@ -56,20 +53,20 @@ public class PropertyCodegen {
(setter == null && isExternallyAccessible(p) && p.isVar()))) {
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
setterName(p.getName()),
mapper.mapSetterSignature(propertyDescriptor).getDescriptor(),
state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor(),
null, null);
}
}
else if (kind instanceof OwnerKind.DelegateKind) {
generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
if (propertyDescriptor.isVar()) {
generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
}
}
}
private void generateBackingField(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) {
if (context.hasBackingField(propertyDescriptor)) {
private void generateBackingField(JetProperty p, PropertyDescriptor propertyDescriptor) {
if (state.getBindingContext().hasBackingField(propertyDescriptor)) {
Object value = null;
final JetExpression initializer = p.getInitializer();
if (initializer != null) {
@@ -85,25 +82,22 @@ public class PropertyCodegen {
else {
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();
if (getter != null) {
if (getter.getBodyExpression() != null) {
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
null,
Collections.<ValueParameterDescriptor>emptyList(),
Collections.<TypeParameterDescriptor>emptyList());
functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor), propertyDescriptor.getGetter());
}
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultGetter(p, getter, kind);
generateDefaultGetter(p, getter);
}
}
else if (isExternallyAccessible(p)) {
generateDefaultGetter(p, p, kind);
generateDefaultGetter(p, p);
}
}
@@ -111,33 +105,30 @@ public class PropertyCodegen {
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();
if (setter != null) {
if (setter.getBodyExpression() != null) {
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
assert setterDescriptor != null;
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor),
null,
setterDescriptor.getValueParameters(),
Collections.<TypeParameterDescriptor>emptyList());
functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor), setterDescriptor);
}
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultSetter(p, setter, kind);
generateDefaultSetter(p, setter);
}
}
else if (isExternallyAccessible(p) && p.isVar()) {
generateDefaultSetter(p, p, kind);
generateDefaultSetter(p, p);
}
}
private void generateDefaultGetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p);
private void generateDefaultGetter(JetProperty p, JetDeclaration declaration) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().getVariableDescriptor(p);
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) {
flags |= Opcodes.ACC_STATIC;
}
@@ -145,7 +136,7 @@ public class PropertyCodegen {
flags |= Opcodes.ACC_ABSTRACT;
}
final String signature = mapper.mapGetterSignature(propertyDescriptor).getDescriptor();
final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor();
String getterName = getterName(propertyDescriptor.getName());
MethodVisitor mv = v.visitMethod(flags, getterName, signature, null, null);
if (kind != OwnerKind.INTERFACE) {
@@ -154,7 +145,7 @@ public class PropertyCodegen {
if (kind != OwnerKind.NAMESPACE) {
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) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
@@ -162,7 +153,7 @@ public class PropertyCodegen {
}
else {
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD,
mapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
state.getTypeMapper().getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
type.getDescriptor());
}
iv.areturn(type);
@@ -171,13 +162,13 @@ public class PropertyCodegen {
}
}
private void generateDefaultSetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p);
private void generateDefaultSetter(JetProperty p, JetDeclaration declaration) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().getVariableDescriptor(p);
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) {
flags |= Opcodes.ACC_STATIC;
}
@@ -185,12 +176,12 @@ public class PropertyCodegen {
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);
if (kind != OwnerKind.INTERFACE) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
final Type type = mapper.mapType(propertyDescriptor.getOutType());
final Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
int paramCode = 0;
if (kind != OwnerKind.NAMESPACE) {
iv.load(0, JetTypeMapper.TYPE_OBJECT);
@@ -208,7 +199,7 @@ public class PropertyCodegen {
else {
iv.load(paramCode, type);
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD,
mapper.getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
state.getTypeMapper().getOwner(propertyDescriptor, kind), propertyDescriptor.getName(),
type.getDescriptor());
}
@@ -71,6 +71,10 @@ public abstract class StackValue {
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) {
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 final String owner;
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 final String name;
private final Method getter;