work in progress on codegen rewrite (no boxing for primitive types)

This commit is contained in:
Dmitry Jemerov
2011-03-28 14:14:41 +02:00
parent d05066f8f5
commit 739fce330c
10 changed files with 194 additions and 83 deletions
@@ -19,15 +19,21 @@ import java.util.Stack;
public class ExpressionCodegen extends JetVisitor { public class ExpressionCodegen extends JetVisitor {
private final Stack<Label> myLoopStarts = new Stack<Label>(); private final Stack<Label> myLoopStarts = new Stack<Label>();
private final Stack<Label> myLoopEnds = new Stack<Label>(); private final Stack<Label> myLoopEnds = new Stack<Label>();
private final Stack<StackValue> myStack = new Stack<StackValue>();
private final InstructionAdapter v; private final InstructionAdapter v;
private final JetStandardLibrary stdlib; private final JetStandardLibrary stdlib;
private final FrameMap myMap; private final FrameMap myMap;
private final JetTypeMapper typeMapper;
private final Type returnType;
private final BindingContext bindingContext; private final BindingContext bindingContext;
public ExpressionCodegen(MethodVisitor v, BindingContext bindingContext, JetStandardLibrary stdlib, FrameMap myMap) { public ExpressionCodegen(MethodVisitor v, BindingContext bindingContext, JetStandardLibrary stdlib, FrameMap myMap,
JetTypeMapper typeMapper, Type returnType) {
this.stdlib = stdlib; this.stdlib = stdlib;
this.myMap = myMap; this.myMap = myMap;
this.typeMapper = typeMapper;
this.returnType = returnType;
this.v = new InstructionAdapter(v); this.v = new InstructionAdapter(v);
this.bindingContext = bindingContext; this.bindingContext = bindingContext;
} }
@@ -37,6 +43,15 @@ public class ExpressionCodegen extends JetVisitor {
expr.accept(this); expr.accept(this);
} }
private void gen(JetElement expr, Type type) {
int oldStackDepth = myStack.size();
gen(expr);
if (myStack.size() == oldStackDepth+1) {
StackValue value = myStack.pop();
value.put(type, v);
}
}
@Override @Override
public void visitExpression(JetExpression expression) { public void visitExpression(JetExpression expression) {
throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented"); throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
@@ -54,8 +69,9 @@ public class ExpressionCodegen extends JetVisitor {
@Override @Override
public void visitIfExpression(JetIfExpression expression) { public void visitIfExpression(JetIfExpression expression) {
gen(expression.getCondition()); JetType expressionType = bindingContext.getExpressionType(expression);
unboxBoolean(); Type asmType = typeMapper.mapType(expressionType);
gen(expression.getCondition(), Type.BOOLEAN_TYPE);
JetExpression thenExpression = expression.getThen(); JetExpression thenExpression = expression.getThen();
JetExpression elseExpression = expression.getElse(); JetExpression elseExpression = expression.getElse();
@@ -78,13 +94,13 @@ public class ExpressionCodegen extends JetVisitor {
Label elseLabel = new Label(); Label elseLabel = new Label();
v.ifeq(elseLabel); // == 0, i.e. false v.ifeq(elseLabel); // == 0, i.e. false
gen(thenExpression); gen(thenExpression, asmType);
Label endLabel = new Label(); Label endLabel = new Label();
v.goTo(endLabel); v.goTo(endLabel);
v.mark(elseLabel); v.mark(elseLabel);
gen(elseExpression); gen(elseExpression, asmType);
v.mark(endLabel); v.mark(endLabel);
} }
@@ -178,6 +194,8 @@ public class ExpressionCodegen extends JetVisitor {
@Override @Override
public void visitConstantExpression(JetConstantExpression expression) { public void visitConstantExpression(JetConstantExpression expression) {
myStack.push(StackValue.constant(expression.getValue()));
/*
Object value = expression.getValue(); Object value = expression.getValue();
v.aconst(value); v.aconst(value);
@@ -205,6 +223,7 @@ public class ExpressionCodegen extends JetVisitor {
else if (value instanceof Double) { else if (value instanceof Double) {
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
} }
*/
} }
@Override @Override
@@ -229,8 +248,11 @@ public class ExpressionCodegen extends JetVisitor {
for (JetElement statement : statements) { for (JetElement statement : statements) {
if (statement instanceof JetProperty) { if (statement instanceof JetProperty) {
JetProperty var = (JetProperty) statement; JetProperty var = (JetProperty) statement;
int index = myMap.leave(bindingContext.getPropertyDescriptor(var)); PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(var);
v.visitLocalVariable(var.getName(), getType(var).getDescriptor(), null, blockStart, blockEnd, index); Type outType = typeMapper.mapType(propertyDescriptor.getOutType());
int index = myMap.leave(propertyDescriptor);
v.visitLocalVariable(var.getName(), outType.getDescriptor(), null, blockStart, blockEnd, index);
} }
} }
@@ -240,14 +262,22 @@ public class ExpressionCodegen extends JetVisitor {
public void visitReturnExpression(JetReturnExpression expression) { public void visitReturnExpression(JetReturnExpression expression) {
final JetExpression returnedExpression = expression.getReturnedExpression(); final JetExpression returnedExpression = expression.getReturnedExpression();
if (returnedExpression != null) { if (returnedExpression != null) {
returnedExpression.accept(this); gen(returnedExpression, returnType);
v.visitInsn(Opcodes.ARETURN); v.areturn(returnType);
} }
else { else {
v.visitInsn(Opcodes.RETURN); v.visitInsn(Opcodes.RETURN);
} }
} }
public void returnTopOfStack() {
if (myStack.size() > 0) {
StackValue value = myStack.pop();
value.put(returnType, v);
v.areturn(returnType);
}
}
@Override @Override
public void visitSimpleNameExpression(JetSimpleNameExpression expression) { public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression); final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression);
@@ -267,7 +297,7 @@ public class ExpressionCodegen extends JetVisitor {
else { else {
int index = myMap.getIndex(descriptor); int index = myMap.getIndex(descriptor);
if (index >= 0) { if (index >= 0) {
v.visitVarInsn(Opcodes.ALOAD, index); myStack.push(StackValue.local(index, ((PropertyDescriptor) descriptor).getOutType()));
} }
else { else {
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
@@ -277,11 +307,6 @@ public class ExpressionCodegen extends JetVisitor {
@Override @Override
public void visitCallExpression(JetCallExpression expression) { public void visitCallExpression(JetCallExpression expression) {
List<JetArgument> args = expression.getValueArguments();
for (JetArgument arg : args) {
gen(arg.getArgumentExpression());
}
JetExpression callee = expression.getCalleeExpression(); JetExpression callee = expression.getCalleeExpression();
if (callee instanceof JetSimpleNameExpression) { if (callee instanceof JetSimpleNameExpression) {
@@ -290,6 +315,14 @@ public class ExpressionCodegen extends JetVisitor {
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor); PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor);
if (declarationPsiElement instanceof PsiMethod) { if (declarationPsiElement instanceof PsiMethod) {
PsiMethod method = (PsiMethod) declarationPsiElement; PsiMethod method = (PsiMethod) declarationPsiElement;
PsiParameter[] parameters = method.getParameterList().getParameters();
List<JetArgument> args = expression.getValueArguments();
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
JetArgument arg = args.get(i);
gen(arg.getArgumentExpression(), psiTypeToAsm(parameters [i].getType()));
}
if (method.hasModifierProperty(PsiModifier.STATIC)) { if (method.hasModifierProperty(PsiModifier.STATIC)) {
v.visitMethodInsn(Opcodes.INVOKESTATIC, v.visitMethodInsn(Opcodes.INVOKESTATIC,
jvmName(method.getContainingClass()), jvmName(method.getContainingClass()),
@@ -302,7 +335,7 @@ public class ExpressionCodegen extends JetVisitor {
method.getName(), method.getName(),
getMethodDescriptor(method)); getMethodDescriptor(method));
} }
boxIfNeeded(method.getReturnType()); myStack.push(StackValue.onStack(psiTypeToAsm(method.getReturnType())));
} }
} }
else { else {
@@ -422,12 +455,10 @@ public class ExpressionCodegen extends JetVisitor {
if (op.getName().equals("plus")) { if (op.getName().equals("plus")) {
JetType returnType = ((FunctionDescriptor) op).getUnsubstitutedReturnType(); JetType returnType = ((FunctionDescriptor) op).getUnsubstitutedReturnType();
if (returnType.equals(stdlib.getIntType())) { if (returnType.equals(stdlib.getIntType())) {
gen(expression.getLeft()); gen(expression.getLeft(), Type.INT_TYPE);
unbox(PsiType.INT); gen(expression.getRight(), Type.INT_TYPE);
gen(expression.getRight());
unbox(PsiType.INT);
v.add(Type.INT_TYPE); v.add(Type.INT_TYPE);
boxIfNeeded(PsiType.INT); myStack.push(StackValue.onStack(Type.INT_TYPE));
return; return;
} }
} }
@@ -436,24 +467,22 @@ public class ExpressionCodegen extends JetVisitor {
throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); throw new UnsupportedOperationException("Don't know how to generate binary op " + expression);
} }
private Type getType(JetProperty var) {
return InstructionAdapter.OBJECT_TYPE; // TODO:
}
private boolean isUnitType(JetExpression e) { private boolean isUnitType(JetExpression e) {
return false; // TODO:!!! return false; // TODO:!!!
} }
@Override @Override
public void visitProperty(JetProperty property) { public void visitProperty(JetProperty property) {
int index = myMap.getIndex(bindingContext.getPropertyDescriptor(property)); PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(property);
int index = myMap.getIndex(propertyDescriptor);
assert index >= 0; assert index >= 0;
JetExpression initializer = property.getInitializer(); JetExpression initializer = property.getInitializer();
if (initializer != null) { if (initializer != null) {
gen(initializer); Type type = typeMapper.mapType(propertyDescriptor.getOutType());
v.store(index, getType(property)); gen(initializer, type);
v.store(index, type);
} }
} }
@@ -56,20 +56,21 @@ public class FunctionCodegen {
frameMap.enter(parameter); frameMap.enter(parameter);
} }
bodyExpression.accept(new ExpressionCodegen(mv, bindingContext, standardLibrary, frameMap)); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, standardLibrary, frameMap, typeMapper, returnType);
generateReturn(mv, bodyExpression); bodyExpression.accept(codegen);
generateReturn(mv, bodyExpression, codegen);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
} }
private void generateReturn(MethodVisitor mv, JetExpression bodyExpression) { private void generateReturn(MethodVisitor mv, JetExpression bodyExpression, ExpressionCodegen codegen) {
if (!endsWithReturn(bodyExpression)) { if (!endsWithReturn(bodyExpression)) {
final JetType expressionType = bindingContext.getExpressionType(bodyExpression); final JetType expressionType = bindingContext.getExpressionType(bodyExpression);
if (expressionType.equals(JetStandardClasses.getUnitType())) { if (expressionType.equals(JetStandardClasses.getUnitType())) {
mv.visitInsn(Opcodes.RETURN); mv.visitInsn(Opcodes.RETURN);
} }
else { else {
mv.visitInsn(Opcodes.ARETURN); codegen.returnTopOfStack();
} }
} }
} }
@@ -18,10 +18,13 @@ public class JetTypeMapper {
return Type.VOID_TYPE; return Type.VOID_TYPE;
} }
if (jetType.equals(standardLibrary.getIntType())) { if (jetType.equals(standardLibrary.getIntType())) {
return Type.getType(Integer.class); return Type.INT_TYPE;
} }
if (jetType.equals(standardLibrary.getLongType())) { if (jetType.equals(standardLibrary.getLongType())) {
return Type.getType(Long.class); return Type.LONG_TYPE;
}
if (jetType.equals(standardLibrary.getBooleanType())) {
return Type.BOOLEAN_TYPE;
} }
if (jetType.equals(standardLibrary.getStringType())) { if (jetType.equals(standardLibrary.getStringType())) {
return Type.getType(String.class); return Type.getType(String.class);
@@ -0,0 +1,76 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
/**
* @author yole
*/
public abstract class StackValue {
public abstract void put(Type type, InstructionAdapter v);
public static StackValue local(int index, JetType type) {
return new Local(index, type);
}
public static StackValue onStack(Type type) {
return new OnStack(type);
}
public static StackValue constant(Object value) {
return new Constant(value);
}
public static class Local extends StackValue {
private final int index;
private final JetType type;
public Local(int index, JetType type) {
this.index = index;
this.type = type;
}
@Override
public void put(Type type, InstructionAdapter v) {
v.load(index, type);
// TODO box/unbox
}
}
public static class OnStack extends StackValue {
private final Type type;
public OnStack(Type type) {
this.type = type;
}
@Override
public void put(Type type, InstructionAdapter v) {
}
}
public static class Constant extends StackValue {
private final Object value;
public Constant(Object value) {
this.value = value;
}
@Override
public void put(Type type, InstructionAdapter v) {
if (type == Type.INT_TYPE) {
if (value instanceof Number) {
v.iconst(((Number) value).intValue());
}
else {
throw new UnsupportedOperationException("don't know how to put this value");
}
}
// TODO other primitive types
else {
v.aconst(value);
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
fun f(): Int {
var x: Int = 1
x = x + 1
return x
}
+1
View File
@@ -0,0 +1 @@
fun foo(b: Boolean): Int { return if (b) 15 else 20 }
+4
View File
@@ -0,0 +1,4 @@
fun foo(b: Boolean) : Int {
if (b) return 15;
return 20;
}
View File
@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetProperty;
import org.objectweb.asm.Type;
import org.objectweb.asm.util.TraceMethodVisitor; import org.objectweb.asm.util.TraceMethodVisitor;
import java.io.IOException; import java.io.IOException;
@@ -13,36 +14,7 @@ import java.io.StringWriter;
* @author max * @author max
*/ */
public class ExpressionGenTest extends LightDaemonAnalyzerTestCase { public class ExpressionGenTest extends LightDaemonAnalyzerTestCase {
public void testIntegerZeroExpression() throws Exception {
checkCode("0",
"LDC 0\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;");
}
public void testIf() throws Exception { public void testIf() throws Exception {
checkCode("if (false) 15 else 20",
"LDC false\n" +
"INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" +
"INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z\n" +
"IFEQ L0\n" +
"LDC 15\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"GOTO L1\n" +
"L0\n" +
"LDC 20\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"L1");
checkCode("if (false) 15",
"LDC false\n" +
"INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" +
"INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z\n" +
"IFEQ L0\n" +
"LDC 15\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"POP\n" +
"L0");
checkCode("if (false) else 20", checkCode("if (false) else 20",
"LDC false\n" + "LDC false\n" +
"INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" + "INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" +
@@ -60,7 +32,7 @@ public class ExpressionGenTest extends LightDaemonAnalyzerTestCase {
JetProperty p = PsiTreeUtil.getParentOfType(getFile().findElementAt(0), JetProperty.class); JetProperty p = PsiTreeUtil.getParentOfType(getFile().findElementAt(0), JetProperty.class);
TraceMethodVisitor trace = new TraceMethodVisitor(); TraceMethodVisitor trace = new TraceMethodVisitor();
p.getInitializer().accept(new ExpressionCodegen(trace, null, null, new FrameMap())); p.getInitializer().accept(new ExpressionCodegen(trace, null, null, new FrameMap(), new JetTypeMapper(null), Type.VOID_TYPE));
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
trace.print(new PrintWriter(out)); trace.print(new PrintWriter(out));
@@ -28,8 +28,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
final String text = generateToText(); final String text = generateToText();
System.out.println(text); System.out.println(text);
final Class aClass = generateToClass(); final Method main = generateFunction();
final Method main = firstMethod(aClass);
Object[] args = new Object[] { new String[0] }; Object[] args = new Object[] { new String[0] };
main.invoke(null, args); main.invoke(null, args);
} }
@@ -39,8 +38,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
final String text = generateToText(); final String text = generateToText();
System.out.println(text); System.out.println(text);
final Class aClass = generateToClass(); final Method main = generateFunction();
final Method main = firstMethod(aClass);
final Object returnValue = main.invoke(null, new Object[0]); final Object returnValue = main.invoke(null, new Object[0]);
assertEquals(new Integer(42), returnValue); assertEquals(new Integer(42), returnValue);
} }
@@ -50,8 +48,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
final String text = generateToText(); final String text = generateToText();
System.out.println(text); System.out.println(text);
final Class aClass = generateToClass(); final Method main = generateFunction();
final Method main = firstMethod(aClass);
final Object returnValue = main.invoke(null, 50); final Object returnValue = main.invoke(null, 50);
assertEquals(new Integer(50), returnValue); assertEquals(new Integer(50), returnValue);
} }
@@ -61,16 +58,15 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
final String text = generateToText(); final String text = generateToText();
System.out.println(text); System.out.println(text);
final Class aClass = generateToClass(); final Method main = generateFunction();
final Method main = firstMethod(aClass);
final Object returnValue = main.invoke(null, 76); final Object returnValue = main.invoke(null, 76);
assertEquals(new Integer(50), returnValue); assertEquals(new Integer(50), returnValue);
} }
public void testCurrentTime() throws Exception { public void testCurrentTime() throws Exception {
loadFile("currentTime.jet"); loadFile("currentTime.jet");
final Class aClass = generateToClass(); System.out.println(generateToText());
final Method main = firstMethod(aClass); final Method main = generateFunction();
final long returnValue = (Long) main.invoke(null); final long returnValue = (Long) main.invoke(null);
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
assertTrue(Math.abs(returnValue - currentTime) <= 1L); assertTrue(Math.abs(returnValue - currentTime) <= 1L);
@@ -78,8 +74,8 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
public void testIdentityHashCode() throws Exception { public void testIdentityHashCode() throws Exception {
loadFile("identityHashCode.jet"); loadFile("identityHashCode.jet");
final Class aClass = generateToClass(); System.out.println(generateToText());
final Method main = firstMethod(aClass); final Method main = generateFunction();
Object o = new Object(); Object o = new Object();
final int returnValue = (Integer) main.invoke(null, o); final int returnValue = (Integer) main.invoke(null, o);
assertEquals(returnValue, System.identityHashCode(o)); assertEquals(returnValue, System.identityHashCode(o));
@@ -87,8 +83,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
public void testSystemOut() throws Exception { public void testSystemOut() throws Exception {
loadFile("systemOut.jet"); loadFile("systemOut.jet");
final Class aClass = generateToClass(); final Method main = generateFunction();
final Method main = firstMethod(aClass);
final Object returnValue = main.invoke(null); final Object returnValue = main.invoke(null);
assertEquals(returnValue, System.out); assertEquals(returnValue, System.out);
} }
@@ -98,8 +93,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
System.out.println(generateToText()); System.out.println(generateToText());
final Class aClass = generateToClass(); generateFunction(); // assert that it can be verified
final Method main = firstMethod(aClass); // assert that it can be verified
} }
public void testPlus() throws Exception { public void testPlus() throws Exception {
@@ -107,12 +101,37 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
System.out.println(generateToText()); System.out.println(generateToText());
final Class aClass = generateToClass(); final Method main = generateFunction();
final Method main = firstMethod(aClass);
final int returnValue = (Integer) main.invoke(null, 37, 5); final int returnValue = (Integer) main.invoke(null, 37, 5);
assertEquals(42, returnValue); assertEquals(42, returnValue);
} }
public void testIf() throws Exception {
loadFile("if.jet");
System.out.println(generateToText());
final Method main = generateFunction();
assertEquals(15, main.invoke(null, true));
assertEquals(20, main.invoke(null, false));
}
public void testSingleBranchIf() throws Exception {
loadFile("singleBranchIf.jet");
System.out.println(generateToText());
final Method main = generateFunction();
assertEquals(15, main.invoke(null, true));
assertEquals(20, main.invoke(null, false));
}
public void testAssign() throws Exception {
loadFile("assign.jet");
System.out.println(generateToText());
final Method main = generateFunction();
assertEquals(2, main.invoke(null));
}
private void loadFile(final String name) { private void loadFile(final String name) {
myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/" + name); myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/" + name);
} }
@@ -143,7 +162,8 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
return aClass; return aClass;
} }
private static Method firstMethod(Class aClass) { private Method generateFunction() {
Class aClass = generateToClass();
return aClass.getMethods()[0]; return aClass.getMethods()[0];
} }