initial support for generating extension functions

This commit is contained in:
Dmitry Jemerov
2011-05-26 19:07:50 +04:00
parent 1dd62a3560
commit 58f50a8046
8 changed files with 84 additions and 28 deletions
@@ -175,7 +175,7 @@ public class ClassCodegen {
frameMap.enterTemp(); // this frameMap.enterTemp(); // this
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, classDescriptor, kind); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, classDescriptor, kind);
String classname = typeMapper.jvmName(classDescriptor, kind); String classname = typeMapper.jvmName(classDescriptor, kind);
final Type classType = Type.getType("L" + classname + ";"); final Type classType = Type.getType("L" + classname + ";");
@@ -66,6 +66,7 @@ public class ExpressionCodegen extends JetVisitor {
private final InstructionAdapter v; private final InstructionAdapter v;
private final FrameMap myMap; private final FrameMap myMap;
private final JetTypeMapper typeMapper; private final JetTypeMapper typeMapper;
private final JetType receiverType;
private final Type returnType; private final Type returnType;
private final DeclarationDescriptor contextType; private final DeclarationDescriptor contextType;
private final OwnerKind contextKind; private final OwnerKind contextKind;
@@ -75,11 +76,13 @@ public class ExpressionCodegen extends JetVisitor {
BindingContext bindingContext, BindingContext bindingContext,
FrameMap myMap, FrameMap myMap,
JetTypeMapper typeMapper, JetTypeMapper typeMapper,
JetType receiverType,
Type returnType, Type returnType,
DeclarationDescriptor contextType, DeclarationDescriptor contextType,
OwnerKind contextKind) { OwnerKind contextKind) {
this.myMap = myMap; this.myMap = myMap;
this.typeMapper = typeMapper; this.typeMapper = typeMapper;
this.receiverType = receiverType;
this.returnType = returnType; this.returnType = returnType;
this.contextType = contextType; this.contextType = contextType;
this.contextKind = contextKind; this.contextKind = contextKind;
@@ -107,11 +110,15 @@ public class ExpressionCodegen extends JetVisitor {
int oldStackDepth = myStack.size(); int oldStackDepth = myStack.size();
gen(expr); gen(expr);
if (myStack.size() == oldStackDepth+1) { if (myStack.size() == oldStackDepth+1) {
StackValue value = myStack.pop(); putTopOfStack(type);
value.put(type, v);
} }
} }
private void putTopOfStack(Type type) {
StackValue value = myStack.pop();
value.put(type, v);
}
public void genToJVMStack(JetExpression expr) { public void genToJVMStack(JetExpression expr) {
gen(expr, expressionType(expr)); gen(expr, expressionType(expr));
} }
@@ -526,8 +533,7 @@ public class ExpressionCodegen extends JetVisitor {
public void returnTopOfStack() { public void returnTopOfStack() {
if (myStack.size() > 0) { if (myStack.size() > 0) {
StackValue value = myStack.pop(); putTopOfStack(returnType);
value.put(returnType, v);
v.areturn(returnType); v.areturn(returnType);
} }
} }
@@ -1354,23 +1360,37 @@ public class ExpressionCodegen extends JetVisitor {
@Override @Override
public void visitThisExpression(JetThisExpression expression) { public void visitThisExpression(JetThisExpression expression) {
thisToStack(); generateThis();
} }
public void thisToStack() { public void thisToStack() {
if (contextKind == OwnerKind.NAMESPACE) { generateThis();
throw new UnsupportedOperationException("Cannot generate this expression in top level context"); putTopOfStack(JetTypeMapper.TYPE_OBJECT);
} }
ClassDescriptor contextClass = (ClassDescriptor) contextType; private void generateThis() {
if (contextKind == OwnerKind.IMPLEMENTATION) { if (contextKind == OwnerKind.NAMESPACE) {
v.load(0, JetTypeMapper.jetImplementationType(contextClass)); if (receiverType != null) {
} myStack.push(StackValue.local(0, typeMapper.mapType(receiverType)));
else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) { }
v.getfield(typeMapper.jvmName(contextClass, contextKind), "$this", JetTypeMapper.jetInterfaceType(contextClass).getDescriptor()); else {
throw new UnsupportedOperationException("Cannot generate this expression in top level context");
}
} }
else { else {
throw new UnsupportedOperationException("Unknown kind: " + contextKind); ClassDescriptor contextClass = (ClassDescriptor) contextType;
if (contextKind == OwnerKind.IMPLEMENTATION) {
myStack.push(StackValue.local(0, JetTypeMapper.jetImplementationType(contextClass)));
}
else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) {
myStack.push(StackValue.field(JetTypeMapper.jetInterfaceType(contextClass),
typeMapper.jvmName(contextClass, contextKind),
"$this",
false));
}
else {
throw new UnsupportedOperationException("Unknown kind: " + contextKind);
}
} }
} }
@@ -1,10 +1,12 @@
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.DeclarationDescriptor;
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.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetStandardLibrary;
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;
@@ -31,12 +33,18 @@ public class FunctionCodegen {
} }
public void gen(JetFunction f, OwnerKind kind) { public void gen(JetFunction f, OwnerKind kind) {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : bindingContext.resolveTypeReference(receiverTypeRef);
Method method = typeMapper.mapSignature(f); Method method = typeMapper.mapSignature(f);
List<ValueParameterDescriptor> paramDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters(); List<ValueParameterDescriptor> paramDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters();
generateMethod(f, kind, method, paramDescrs); generateMethod(f, kind, method, receiverType, paramDescrs);
} }
public void generateMethod(JetDeclarationWithBody f, OwnerKind kind, Method jvmSignature, List<ValueParameterDescriptor> paramDescrs) { public void generateMethod(JetDeclarationWithBody f,
OwnerKind kind,
Method jvmSignature,
@Nullable JetType receiverType,
List<ValueParameterDescriptor> paramDescrs) {
int flags = Opcodes.ACC_PUBLIC; // TODO. int flags = Opcodes.ACC_PUBLIC; // TODO.
boolean isStatic = kind == OwnerKind.NAMESPACE; boolean isStatic = kind == OwnerKind.NAMESPACE;
@@ -55,7 +63,7 @@ public class FunctionCodegen {
mv.visitCode(); mv.visitCode();
FrameMap frameMap = new FrameMap(); FrameMap frameMap = new FrameMap();
if (kind != OwnerKind.NAMESPACE) { if (kind != OwnerKind.NAMESPACE || receiverType != null) {
frameMap.enterTemp(); // 0 slot for this frameMap.enterTemp(); // 0 slot for this
} }
@@ -65,7 +73,8 @@ public class FunctionCodegen {
frameMap.enter(parameter, argTypes[i].getSize()); frameMap.enter(parameter, argTypes[i].getSize());
} }
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, jvmSignature.getReturnType(), contextDescriptor, kind); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, receiverType,
jvmSignature.getReturnType(), contextDescriptor, kind);
if (kind instanceof OwnerKind.DelegateKind) { if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -206,10 +206,15 @@ public class JetTypeMapper {
} }
public Method mapSignature(JetFunction f) { public Method mapSignature(JetFunction f) {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : bindingContext.resolveTypeReference(receiverTypeRef);
final List<JetParameter> parameters = f.getValueParameters(); final List<JetParameter> parameters = f.getValueParameters();
Type[] parameterTypes = new Type[parameters.size()]; List<Type> parameterTypes = new ArrayList<Type>();
for (int i = 0; i < parameters.size(); i++) { if (receiverType != null) {
parameterTypes[i] = mapType(bindingContext.resolveTypeReference(parameters.get(i).getTypeReference())); parameterTypes.add(mapType(receiverType));
}
for (JetParameter parameter : parameters) {
parameterTypes.add(mapType(bindingContext.resolveTypeReference(parameter.getTypeReference())));
} }
final JetTypeReference returnTypeRef = f.getReturnTypeRef(); final JetTypeReference returnTypeRef = f.getReturnTypeRef();
Type returnType; Type returnType;
@@ -221,7 +226,7 @@ public class JetTypeMapper {
else { else {
returnType = mapType(bindingContext.resolveTypeReference(returnTypeRef)); returnType = mapType(bindingContext.resolveTypeReference(returnTypeRef));
} }
return new Method(f.getName(), returnType, parameterTypes); return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
} }
public Method mapGetterSignature(PropertyDescriptor descriptor) { public Method mapGetterSignature(PropertyDescriptor descriptor) {
@@ -13,7 +13,6 @@ import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; 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 org.objectweb.asm.commons.Method;
/** /**
* @author max * @author max
@@ -72,7 +71,7 @@ public class NamespaceCodegen {
FrameMap frameMap = new FrameMap(); FrameMap frameMap = new FrameMap();
JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext); JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext);
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, null, OwnerKind.NAMESPACE); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, null, OwnerKind.NAMESPACE);
for (JetDeclaration declaration : namespace.getDeclarations()) { for (JetDeclaration declaration : namespace.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
@@ -96,7 +96,7 @@ public class PropertyCodegen {
if (getter != null) { if (getter != null) {
if (getter.getBodyExpression() != null) { if (getter.getBodyExpression() != null) {
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor), functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
Collections.<ValueParameterDescriptor>emptyList()); null, Collections.<ValueParameterDescriptor>emptyList());
} }
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) { else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultGetter(p, getter, kind); generateDefaultGetter(p, getter, kind);
@@ -118,7 +118,7 @@ public class PropertyCodegen {
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, kind, mapper.mapSetterSignature(propertyDescriptor),
setterDescriptor.getUnsubstitutedValueParameters()); null, setterDescriptor.getUnsubstitutedValueParameters());
} }
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) { else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultSetter(p, setter, kind); generateDefaultSetter(p, setter, kind);
@@ -0,0 +1,3 @@
fun StringBuilder.first() = this.charAt(0)
fun foo() = new StringBuilder("foo").first()
@@ -0,0 +1,20 @@
package org.jetbrains.jet.codegen;
import java.lang.reflect.Method;
/**
* @author yole
*/
public class ExtensionFunctionsTest extends CodegenTestCase {
@Override
protected String getPrefix() {
return "extensionFunctions";
}
public void testSimple() throws Exception {
loadFile();
final Method foo = generateFunction("foo");
final Character c = (Character) foo.invoke(null);
assertEquals('f', c.charValue());
}
}