PSVM generation works

This commit is contained in:
Dmitry Jemerov
2011-02-25 18:45:13 +03:00
parent d74052b642
commit 8f1f89cca8
3 changed files with 89 additions and 6 deletions
@@ -1,9 +1,13 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import java.util.List;
/** /**
* @author max * @author max
@@ -16,7 +20,42 @@ public class FunctionCodegen {
} }
public void gen(JetFunction f, JetNamespace owner) { public void gen(JetFunction f, JetNamespace owner) {
final List<JetParameter> parameters = f.getValueParameters();
Type[] parameterTypes = new Type[parameters.size()];
for (int i = 0; i < parameters.size(); i++) {
parameterTypes[i] = mapTypeReference(parameters.get(i).getTypeReference());
}
Method method = new Method(f.getName(), Type.VOID_TYPE, parameterTypes);
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
method.getName(), method.getDescriptor(), null, null);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
private Type mapTypeReference(JetTypeReference typeRef) {
if (typeRef == null) {
throw new UnsupportedOperationException("Cannot evaluate type for parameter with no type ref");
}
final JetTypeElement typeElement = typeRef.getTypeElement();
if (typeElement instanceof JetUserType) {
final String referencedName = ((JetUserType) typeElement).getReferencedName();
if ("Array".equals(referencedName)) {
final List<JetTypeProjection> typeArguments = ((JetUserType) typeElement).getTypeArguments();
if (typeArguments.size() != 1) {
throw new UnsupportedOperationException("arrays must have one type argument");
}
final JetTypeReference elementTypeRef = typeArguments.get(0).getTypeReference();
Type elementType = mapTypeReference(elementTypeRef);
return Type.getType("[" + elementType.getDescriptor());
}
if ("String".equals(referencedName)) {
return Type.getType(String.class);
}
}
throw new UnsupportedOperationException("Unknown type " + typeRef);
} }
public void gen(JetFunction f, JetClass owner) { public void gen(JetFunction f, JetClass owner) {
@@ -19,9 +19,10 @@ public class NamespaceCodegen {
final FunctionCodegen functionCodegen = new FunctionCodegen(v); final FunctionCodegen functionCodegen = new FunctionCodegen(v);
v.visit(Opcodes.V1_6, v.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC,
namespace.getFQName().replace('.', '/') + "/namespace", getJVMClassName(namespace),
null, null,
"jet/lang/Namespace", //"jet/lang/Namespace",
"java/lang/Object",
new String[0] new String[0]
); );
@@ -37,4 +38,8 @@ public class NamespaceCodegen {
v.visitEnd(); v.visitEnd();
} }
public static String getJVMClassName(JetNamespace namespace) {
return namespace.getFQName().replace('.', '/') + "/namespace";
}
} }
@@ -4,21 +4,60 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.parsing.JetParsingTest; import org.jetbrains.jet.parsing.JetParsingTest;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.util.TraceClassVisitor; import org.objectweb.asm.util.TraceClassVisitor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/** /**
* @author yole * @author yole
*/ */
public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
public void testPSVM() { public void testPSVM() throws InvocationTargetException, IllegalAccessException {
myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/PSVM.jet"); myFixture.configureByFile(JetParsingTest.getTestDataDir() + "/codegen/PSVM.jet");
JetFile jetFile = (JetFile) myFixture.getFile(); JetFile jetFile = (JetFile) myFixture.getFile();
JetNamespace namespace = jetFile.getRootNamespace(); JetNamespace namespace = jetFile.getRootNamespace();
NamespaceCodegen codegen = new NamespaceCodegen(); NamespaceCodegen codegen = new NamespaceCodegen();
final String text = generateToText(namespace, codegen);
System.out.println(text);
final Class aClass = generateToClass(namespace, codegen);
final Method[] methods = aClass.getMethods();
final Method main = methods[0];
Object[] args = new Object[] { new String[0] };
main.invoke(null, args);
}
private static String generateToText(JetNamespace namespace, NamespaceCodegen codegen) {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
codegen.generate(namespace, new TraceClassVisitor(new PrintWriter(writer))); codegen.generate(namespace, new TraceClassVisitor(new PrintWriter(writer)));
return writer.toString();
}
private static Class generateToClass(JetNamespace namespace, NamespaceCodegen codegen) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
codegen.generate(namespace, writer);
final byte[] data = writer.toByteArray();
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace).replace("/", "."), data);
return aClass;
}
private static class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class doDefineClass(String name, byte[] data) {
return defineClass(name, data, 0, data.length);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
} }
} }