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) {
|
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();
|
final List<JetParameter> parameters = f.getValueParameters();
|
||||||
Type[] parameterTypes = new Type[parameters.size()];
|
Type[] parameterTypes = new Type[parameters.size()];
|
||||||
for (int i = 0; i < parameters.size(); i++) {
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
@@ -83,8 +91,4 @@ public class FunctionCodegen {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void gen(JetFunction f, JetClass owner) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,18 +83,9 @@ public class JetTypeMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor instanceof ClassDescriptor) {
|
if (descriptor instanceof ClassDescriptor) {
|
||||||
return Type.getObjectType(getFQName(descriptor).replace('.', '/'));
|
return Type.getObjectType(CodeGenUtil.getInternalInterfaceName((ClassDescriptor) descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Unknown type " + jetType);
|
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.psi.PsiManager;
|
||||||
import com.intellij.util.Chunk;
|
import com.intellij.util.Chunk;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.codegen.Codegens;
|
||||||
import org.jetbrains.jet.codegen.NamespaceCodegen;
|
import org.jetbrains.jet.codegen.NamespaceCodegen;
|
||||||
import org.jetbrains.jet.lang.JetFileType;
|
import org.jetbrains.jet.lang.JetFileType;
|
||||||
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.objectweb.asm.ClassWriter;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +65,7 @@ public class JetCompiler implements TranslatingCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class ModuleCompileState {
|
private static class ModuleCompileState {
|
||||||
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
private final Codegens codegens;
|
||||||
private final CompileContext compileContext;
|
private final CompileContext compileContext;
|
||||||
private final Module module;
|
private final Module module;
|
||||||
private final OutputSink outputSink;
|
private final OutputSink outputSink;
|
||||||
@@ -73,6 +74,7 @@ public class JetCompiler implements TranslatingCompiler {
|
|||||||
this.compileContext = compileContext;
|
this.compileContext = compileContext;
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.outputSink = outputSink;
|
this.outputSink = outputSink;
|
||||||
|
codegens = new Codegens(compileContext.getProject(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void compile(final VirtualFile virtualFile) {
|
public void compile(final VirtualFile virtualFile) {
|
||||||
@@ -82,13 +84,7 @@ public class JetCompiler implements TranslatingCompiler {
|
|||||||
PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(virtualFile);
|
PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(virtualFile);
|
||||||
if (psiFile instanceof JetFile) {
|
if (psiFile instanceof JetFile) {
|
||||||
final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace();
|
final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace();
|
||||||
String fqName = namespace.getFQName();
|
NamespaceCodegen codegen = codegens.forNamespace(namespace);
|
||||||
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);
|
|
||||||
}
|
|
||||||
codegen.generate(namespace);
|
codegen.generate(namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,28 +93,15 @@ public class JetCompiler implements TranslatingCompiler {
|
|||||||
|
|
||||||
public void done() {
|
public void done() {
|
||||||
VirtualFile outputDir = compileContext.getModuleOutputDirectory(module);
|
VirtualFile outputDir = compileContext.getModuleOutputDirectory(module);
|
||||||
|
List<String> files = codegens.files();
|
||||||
for (Map.Entry<String, NamespaceCodegen> entry : ns2codegen.entrySet()) {
|
for (String file : files) {
|
||||||
NamespaceCodegen codegen = entry.getValue();
|
File target = new File(outputDir.getPath(), file);
|
||||||
codegen.done();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File nsOutputDir = dirForPackage(outputDir, entry.getKey());
|
FileUtil.writeToFile(target, codegens.asBytes(file));
|
||||||
ClassWriter writer = (ClassWriter) codegen.getVisitor();
|
|
||||||
File output = new File(nsOutputDir, "namespace.class");
|
|
||||||
FileUtil.writeToFile(output, writer.toByteArray());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
compileContext.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, 0, 0);
|
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.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 java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yole
|
* @author yole
|
||||||
@@ -497,29 +494,31 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String generateToText() {
|
private String generateToText() {
|
||||||
StringWriter writer = new StringWriter();
|
Codegens state = new Codegens(getProject(), true);
|
||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
JetNamespace namespace = jetFile.getRootNamespace();
|
JetNamespace namespace = jetFile.getRootNamespace();
|
||||||
NamespaceCodegen codegen = new NamespaceCodegen(getProject(),
|
NamespaceCodegen codegen = state.forNamespace(namespace);
|
||||||
new TraceClassVisitor(new PrintWriter(writer)),
|
|
||||||
namespace.getFQName());
|
|
||||||
codegen.generate(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() {
|
private Class generateToClass() {
|
||||||
|
Codegens state = new Codegens(getProject(), false);
|
||||||
JetFile jetFile = (JetFile) myFixture.getFile();
|
JetFile jetFile = (JetFile) myFixture.getFile();
|
||||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
|
||||||
final JetNamespace namespace = jetFile.getRootNamespace();
|
final JetNamespace namespace = jetFile.getRootNamespace();
|
||||||
NamespaceCodegen codegen = new NamespaceCodegen(getProject(),
|
|
||||||
writer,
|
NamespaceCodegen codegen = state.forNamespace(namespace);
|
||||||
namespace.getFQName());
|
|
||||||
codegen.generate(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());
|
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
|
||||||
final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data);
|
return classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."), data);
|
||||||
return aClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method generateFunction() {
|
private Method generateFunction() {
|
||||||
|
|||||||
Reference in New Issue
Block a user