prepare for multiple classfiles per class generation.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class ClassCodegen {
|
||||
private final Project project;
|
||||
private final ClassVisitor v;
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
public ClassCodegen(Project project, Codegens v, JetClass jetClass, BindingContext bindingContext) {
|
||||
this.project = project;
|
||||
this.v = null;
|
||||
this.bindingContext = bindingContext;
|
||||
|
||||
ClassDescriptor descriptor = bindingContext.getClassDescriptor(jetClass);
|
||||
String fqName = CodeGenUtil.getInternalInterfaceName(descriptor);
|
||||
|
||||
List<JetDelegationSpecifier> delegationSpecifiers = jetClass.getDelegationSpecifiers();
|
||||
for (JetDelegationSpecifier specifier : delegationSpecifiers) {
|
||||
JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference());
|
||||
String superClassFQN = CodeGenUtil.getInternalInterfaceName((ClassDescriptor) superType.getConstructor().getDeclarationDescriptor());
|
||||
}
|
||||
//descriptor.
|
||||
|
||||
/*
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
fqName.replace('.', '/'),
|
||||
null,
|
||||
//"jet/lang/Namespace",
|
||||
"java/lang/Object",
|
||||
new String[0]
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
public void generate(JetNamespace namespace) {
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext);
|
||||
|
||||
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.gen((JetProperty) declaration, namespace);
|
||||
}
|
||||
else if (declaration instanceof JetFunction) {
|
||||
functionCodegen.gen((JetFunction) declaration, namespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ClassVisitor getVisitor() {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class ClassVisitorFactory {
|
||||
public ClassVisitor visitorForClassIn(JetNamespace namespace) {
|
||||
return new TraceClassVisitor(new PrintWriter(new StringWriter()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.types.ClassDescriptor;
|
||||
import org.jetbrains.jet.resolve.DescriptorUtil;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class CodeGenUtil {
|
||||
public static String getInternalInterfaceName(ClassDescriptor descriptor) {
|
||||
return DescriptorUtil.getFQName(descriptor).replace('.', '/');
|
||||
}
|
||||
|
||||
public static String getInternalImplementationName(ClassDescriptor descriptor) {
|
||||
return getInternalInterfaceName(descriptor) + "$$Impl";
|
||||
}
|
||||
|
||||
public static String getInternalDelegatingImplementationName(ClassDescriptor descriptor) {
|
||||
return getInternalInterfaceName(descriptor) + "$$DImpl";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class Codegens {
|
||||
private final Project project;
|
||||
private final boolean isText;
|
||||
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||
private final Map<String, ClassVisitor> generators = new HashMap<String, ClassVisitor>();
|
||||
private boolean isDone = false;
|
||||
|
||||
public Codegens(Project project, boolean text) {
|
||||
this.project = project;
|
||||
isText = text;
|
||||
}
|
||||
|
||||
public ClassVisitor newVisitor(String filePath) {
|
||||
ClassVisitor visitor;
|
||||
if (isText) {
|
||||
visitor = new TraceClassVisitor(new PrintWriter(new StringWriter()));
|
||||
}
|
||||
else {
|
||||
visitor = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
}
|
||||
|
||||
generators.put(filePath, visitor);
|
||||
return visitor;
|
||||
}
|
||||
|
||||
public NamespaceCodegen forNamespace(JetNamespace namespace) {
|
||||
assert !isDone : "Already done!";
|
||||
String fqName = namespace.getFQName();
|
||||
NamespaceCodegen codegen = ns2codegen.get(fqName);
|
||||
if (codegen == null) {
|
||||
codegen = new NamespaceCodegen(project, newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"), fqName);
|
||||
ns2codegen.put(fqName, codegen);
|
||||
}
|
||||
|
||||
return codegen;
|
||||
}
|
||||
|
||||
private void done() {
|
||||
if (!isDone) {
|
||||
isDone = true;
|
||||
for (NamespaceCodegen codegen : ns2codegen.values()) {
|
||||
codegen.done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String asText(String file) {
|
||||
assert isText : "Need to create with text=true";
|
||||
|
||||
done();
|
||||
|
||||
TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file);
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
visitor.print(new PrintWriter(writer));
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public byte[] asBytes(String file) {
|
||||
assert !isText : "This is debug stuff, only produces texts.";
|
||||
|
||||
done();
|
||||
|
||||
ClassWriter visitor = (ClassWriter) generators.get(file);
|
||||
return visitor.toByteArray();
|
||||
}
|
||||
|
||||
public List<String> files() {
|
||||
done();
|
||||
return new ArrayList<String>(generators.keySet());
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,14 @@ public class FunctionCodegen {
|
||||
}
|
||||
|
||||
public void gen(JetFunction f, JetNamespace owner) {
|
||||
gen(f);
|
||||
}
|
||||
|
||||
public void gen(JetFunction f, JetClass owner) {
|
||||
|
||||
}
|
||||
|
||||
private void gen(JetFunction f) {
|
||||
final List<JetParameter> parameters = f.getValueParameters();
|
||||
Type[] parameterTypes = new Type[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
@@ -83,8 +91,4 @@ public class FunctionCodegen {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void gen(JetFunction f, JetClass owner) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,18 +83,9 @@ public class JetTypeMapper {
|
||||
}
|
||||
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return Type.getObjectType(getFQName(descriptor).replace('.', '/'));
|
||||
return Type.getObjectType(CodeGenUtil.getInternalInterfaceName((ClassDescriptor) descriptor));
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown type " + jetType);
|
||||
}
|
||||
|
||||
private static String getFQName(DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container != null && !(container instanceof ModuleDescriptor)) {
|
||||
return getFQName(container) + "." + descriptor.getName();
|
||||
}
|
||||
|
||||
return descriptor.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,15 +12,16 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.Chunk;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.Codegens;
|
||||
import org.jetbrains.jet.codegen.NamespaceCodegen;
|
||||
import org.jetbrains.jet.lang.JetFileType;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,7 @@ public class JetCompiler implements TranslatingCompiler {
|
||||
}
|
||||
|
||||
private static class ModuleCompileState {
|
||||
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||
private final Codegens codegens;
|
||||
private final CompileContext compileContext;
|
||||
private final Module module;
|
||||
private final OutputSink outputSink;
|
||||
@@ -73,6 +74,7 @@ public class JetCompiler implements TranslatingCompiler {
|
||||
this.compileContext = compileContext;
|
||||
this.module = module;
|
||||
this.outputSink = outputSink;
|
||||
codegens = new Codegens(compileContext.getProject(), false);
|
||||
}
|
||||
|
||||
public void compile(final VirtualFile virtualFile) {
|
||||
@@ -82,13 +84,7 @@ public class JetCompiler implements TranslatingCompiler {
|
||||
PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(virtualFile);
|
||||
if (psiFile instanceof JetFile) {
|
||||
final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace();
|
||||
String fqName = namespace.getFQName();
|
||||
NamespaceCodegen codegen = ns2codegen.get(fqName);
|
||||
if (codegen == null) {
|
||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
codegen = new NamespaceCodegen(compileContext.getProject(), writer, fqName);
|
||||
ns2codegen.put(fqName, codegen);
|
||||
}
|
||||
NamespaceCodegen codegen = codegens.forNamespace(namespace);
|
||||
codegen.generate(namespace);
|
||||
}
|
||||
}
|
||||
@@ -97,28 +93,15 @@ public class JetCompiler implements TranslatingCompiler {
|
||||
|
||||
public void done() {
|
||||
VirtualFile outputDir = compileContext.getModuleOutputDirectory(module);
|
||||
|
||||
for (Map.Entry<String, NamespaceCodegen> entry : ns2codegen.entrySet()) {
|
||||
NamespaceCodegen codegen = entry.getValue();
|
||||
codegen.done();
|
||||
|
||||
List<String> files = codegens.files();
|
||||
for (String file : files) {
|
||||
File target = new File(outputDir.getPath(), file);
|
||||
try {
|
||||
File nsOutputDir = dirForPackage(outputDir, entry.getKey());
|
||||
ClassWriter writer = (ClassWriter) codegen.getVisitor();
|
||||
File output = new File(nsOutputDir, "namespace.class");
|
||||
FileUtil.writeToFile(output, writer.toByteArray());
|
||||
FileUtil.writeToFile(target, codegens.asBytes(file));
|
||||
} catch (IOException e) {
|
||||
compileContext.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static File dirForPackage(VirtualFile root, String fqName) throws IOException {
|
||||
File result = new File(root.getPath(), fqName.replace(".", "/"));
|
||||
if (!result.exists() && !result.mkdirs()) {
|
||||
throw new IOException("Failed to create directory for package");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,4 +125,13 @@ public class DescriptorUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFQName(DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container != null && !(container instanceof ModuleDescriptor)) {
|
||||
return getFQName(container) + "." + descriptor.getName();
|
||||
}
|
||||
|
||||
return descriptor.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,10 @@ import org.jetbrains.jet.lang.JetFileType;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -497,29 +494,31 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
private String generateToText() {
|
||||
StringWriter writer = new StringWriter();
|
||||
Codegens state = new Codegens(getProject(), true);
|
||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||
JetNamespace namespace = jetFile.getRootNamespace();
|
||||
NamespaceCodegen codegen = new NamespaceCodegen(getProject(),
|
||||
new TraceClassVisitor(new PrintWriter(writer)),
|
||||
namespace.getFQName());
|
||||
NamespaceCodegen codegen = state.forNamespace(namespace);
|
||||
codegen.generate(namespace);
|
||||
codegen.done();
|
||||
return writer.toString();
|
||||
|
||||
List<String> files = state.files();
|
||||
assertEquals("This test only supposed to generate single class file", 1, files.size());
|
||||
|
||||
return state.asText(files.get(0));
|
||||
}
|
||||
|
||||
private Class generateToClass() {
|
||||
Codegens state = new Codegens(getProject(), false);
|
||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
final JetNamespace namespace = jetFile.getRootNamespace();
|
||||
NamespaceCodegen codegen = new NamespaceCodegen(getProject(),
|
||||
writer,
|
||||
namespace.getFQName());
|
||||
|
||||
NamespaceCodegen codegen = state.forNamespace(namespace);
|
||||
codegen.generate(namespace);
|
||||
final byte[] data = writer.toByteArray();
|
||||
|
||||
List<String> files = state.files();
|
||||
assertEquals("This test only supposed to generate single class file", 1, files.size());
|
||||
final byte[] data = state.asBytes(files.get(0));
|
||||
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
|
||||
final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data);
|
||||
return aClass;
|
||||
return classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data);
|
||||
}
|
||||
|
||||
private Method generateFunction() {
|
||||
|
||||
Reference in New Issue
Block a user