one more step to multi-file compilation

This commit is contained in:
Alex Tkachman
2012-06-06 12:17:25 +03:00
parent 03c4e755fa
commit 7d938dd98f
5 changed files with 84 additions and 64 deletions
@@ -61,13 +61,12 @@ public class ClassFileFactory {
return newVisitor(className.getInternalName() + ".class"); return newVisitor(className.getInternalName() + ".class");
} }
NamespaceCodegen forNamespace(JetFile file) { NamespaceCodegen forNamespace(FqName fqName, Collection<JetFile> files) {
assert !isDone : "Already done!"; assert !isDone : "Already done!";
FqName fqName = JetPsiUtil.getFQName(file);
NamespaceCodegen codegen = ns2codegen.get(fqName); NamespaceCodegen codegen = ns2codegen.get(fqName);
if (codegen == null) { if (codegen == null) {
final ClassBuilder builder = newVisitor(NamespaceCodegen.getJVMClassNameForKotlinNs(fqName).getInternalName() + ".class"); final ClassBuilder builder = newVisitor(NamespaceCodegen.getJVMClassNameForKotlinNs(fqName).getInternalName() + ".class");
codegen = new NamespaceCodegen(builder, fqName, state, file.getContainingFile()); codegen = new NamespaceCodegen(builder, fqName, state, files);
ns2codegen.put(fqName, codegen); ns2codegen.put(fqName, codegen);
} }
@@ -119,42 +119,25 @@ public class GenerationState {
return Pair.create(className, getFactory().forAnonymousSubclass(className)); return Pair.create(className, getFactory().forAnonymousSubclass(className));
} }
public NamespaceCodegen forNamespace(JetFile namespace) { public NamespaceCodegen forNamespace(FqName fqName, Collection<JetFile> namespace) {
return getFactory().forNamespace(namespace); return getFactory().forNamespace(fqName, namespace);
} }
public void compileCorrectFiles(@NotNull CompilationErrorHandler errorHandler) { public void compileCorrectFiles(@NotNull CompilationErrorHandler errorHandler) {
MultiMap<String, JetFile> namespaceGrouping = new MultiMap<String, JetFile>(); MultiMap<FqName, JetFile> namespaceGrouping = new MultiMap<FqName, JetFile>();
for (JetFile file : this.files) { for (JetFile file : this.files) {
if (file == null) throw new IllegalArgumentException("A null file given for compilation"); if (file == null) throw new IllegalArgumentException("A null file given for compilation");
namespaceGrouping.putValue(JetPsiUtil.getFQName(file).getFqName(), file); namespaceGrouping.putValue(JetPsiUtil.getFQName(file), file);
} }
for (Map.Entry<String, Collection<JetFile>> entry : namespaceGrouping.entrySet()) { for (Map.Entry<FqName, Collection<JetFile>> entry : namespaceGrouping.entrySet()) {
for (JetFile file : entry.getValue()) { generateNamespace(entry.getKey(), entry.getValue(), errorHandler, progress);
VirtualFile vFile = file.getVirtualFile();
String path = vFile != null ? vFile.getPath() : "no_virtual_file/" + file.getName();
progress.log("For source: " + path + "\tFor namespace: " + entry.getKey());
try {
generateNamespace(file);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
errorHandler.reportException(e, vFile == null ? "no file" : vFile.getUrl());
DiagnosticUtils.throwIfRunningOnServer(e);
if (ApplicationManager.getApplication().isInternal()) {
e.printStackTrace();
}
}
}
} }
} }
protected void generateNamespace(JetFile namespace) { protected void generateNamespace(FqName fqName, Collection<JetFile> namespace, CompilationErrorHandler errorHandler, Progress progress) {
NamespaceCodegen codegen = forNamespace(namespace); NamespaceCodegen codegen = forNamespace(fqName, namespace);
codegen.generate(namespace); codegen.generate(errorHandler, progress);
} }
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ObjectOrClosureCodegen closure) { public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ObjectOrClosureCodegen closure) {
@@ -16,19 +16,26 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
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.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.utils.Progress;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
import java.util.Collection;
import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Opcodes.*;
/** /**
@@ -36,12 +43,17 @@ import static org.objectweb.asm.Opcodes.*;
*/ */
public class NamespaceCodegen { public class NamespaceCodegen {
private final ClassBuilder v; private final ClassBuilder v;
@NotNull private final FqName name;
private final GenerationState state; private final GenerationState state;
private final Collection<JetFile> files;
public NamespaceCodegen(ClassBuilder v, @NotNull FqName fqName, GenerationState state, PsiFile sourceFile) { public NamespaceCodegen(ClassBuilder v, @NotNull FqName fqName, GenerationState state, Collection<JetFile> files) {
this.v = v; this.v = v;
name = fqName;
this.state = state; this.state = state;
this.files = files;
PsiFile sourceFile = files.iterator().next().getContainingFile();
v.defineClass(sourceFile, V1_6, v.defineClass(sourceFile, V1_6,
ACC_PUBLIC/*|ACC_SUPER*/, ACC_PUBLIC/*|ACC_SUPER*/,
getJVMClassNameForKotlinNs(fqName).getInternalName(), getJVMClassNameForKotlinNs(fqName).getInternalName(),
@@ -54,8 +66,32 @@ public class NamespaceCodegen {
v.visitSource(sourceFile.getName(), null); v.visitSource(sourceFile.getName(), null);
} }
public void generate(JetFile file) { public void generate(CompilationErrorHandler errorHandler, Progress progress) {
for (JetFile file : files) {
VirtualFile vFile = file.getVirtualFile();
try {
String path = vFile != null ? vFile.getPath() : "no_virtual_file/" + file.getName();
if(progress != null) progress.log("For source: " + path);
generate(file);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
if(errorHandler != null) errorHandler.reportException(e, vFile == null ? "no file" : vFile.getUrl());
DiagnosticUtils.throwIfRunningOnServer(e);
if (ApplicationManager.getApplication().isInternal()) {
e.printStackTrace();
}
}
}
if (hasNonConstantPropertyInitializers()) {
generateStaticInitializers();
}
}
private void generate(JetFile file) {
for (JetDeclaration declaration : file.getDeclarations()) { for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) { if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
@@ -71,54 +107,54 @@ public class NamespaceCodegen {
else if (declaration instanceof JetScript) { else if (declaration instanceof JetScript) {
state.getInjector().getScriptCodegen().generate((JetScript) declaration); state.getInjector().getScriptCodegen().generate((JetScript) declaration);
} }
// else if (declaration instanceof JetFile) {
// JetFile childNamespace = (JetFile) declaration;
// state.forNamespace(childNamespace).generate(childNamespace);
// }
}
if (hasNonConstantPropertyInitializers(file)) {
generateStaticInitializers(file);
} }
} }
private void generateStaticInitializers(JetFile namespace) { private void generateStaticInitializers() {
JetFile namespace = files.iterator().next(); // @todo: hack
MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null); MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { for (JetFile file : files) {
mv.visitCode(); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
FrameMap frameMap = new FrameMap(); FrameMap frameMap = new FrameMap();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state);
for (JetDeclaration declaration : namespace.getDeclarations()) { for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
final JetExpression initializer = ((JetProperty) declaration).getInitializer(); final JetExpression initializer = ((JetProperty) declaration).getInitializer();
if (initializer != null && !(initializer instanceof JetConstantExpression)) { if (initializer != null && !(initializer instanceof JetConstantExpression)) {
final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration); final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
assert descriptor != null; assert descriptor != null;
if(descriptor.getReceiverParameter().exists()) { if(descriptor.getReceiverParameter().exists()) {
continue; continue;
}
codegen.genToJVMStack(initializer);
codegen.intermediateValueForProperty(descriptor, true, null).store(new InstructionAdapter(mv));
} }
codegen.genToJVMStack(initializer);
codegen.intermediateValueForProperty(descriptor, true, null).store(new InstructionAdapter(mv));
} }
} }
} }
}
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace); FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace);
mv.visitEnd(); mv.visitEnd();
} }
} }
private static boolean hasNonConstantPropertyInitializers(JetFile namespace) { private boolean hasNonConstantPropertyInitializers() {
for (JetDeclaration declaration : namespace.getDeclarations()) { for (JetFile file : files) {
if (declaration instanceof JetProperty) { for (JetDeclaration declaration : file.getDeclarations()) {
final JetExpression initializer = ((JetProperty) declaration).getInitializer(); if (declaration instanceof JetProperty) {
if (initializer != null && !(initializer instanceof JetConstantExpression)) { final JetExpression initializer = ((JetProperty) declaration).getInitializer();
return true; if (initializer != null && !(initializer instanceof JetConstantExpression)) {
} return true;
}
}
} }
} }
return false; return false;
@@ -52,8 +52,10 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.util.QualifiedNamesUtil; import org.jetbrains.jet.util.QualifiedNamesUtil;
import org.jetbrains.jet.utils.Progress;
import javax.swing.*; import javax.swing.*;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMarker { public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMarker {
@@ -178,7 +180,7 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa
final GenerationState state = new GenerationState(project, builderFactory, context, Collections.singletonList(file)) { final GenerationState state = new GenerationState(project, builderFactory, context, Collections.singletonList(file)) {
@Override @Override
protected void generateNamespace(JetFile namespace) { protected void generateNamespace(FqName fqName, Collection<JetFile> namespace, CompilationErrorHandler errorHandler, Progress progress) {
PsiManager manager = PsiManager.getInstance(project); PsiManager manager = PsiManager.getInstance(project);
stubStack.push(answer); stubStack.push(answer);
@@ -195,7 +197,7 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa
fakeFile.setPhysical(false); fakeFile.setPhysical(false);
answer.setPsi(fakeFile); answer.setPsi(fakeFile);
super.generateNamespace(namespace); super.generateNamespace(fqName, namespace, errorHandler, progress);
final StubElement pop = stubStack.pop(); final StubElement pop = stubStack.pop();
if (pop != answer) { if (pop != answer) {
LOG.error("Unbalanced stack operations: " + pop); LOG.error("Unbalanced stack operations: " + pop);
@@ -78,7 +78,7 @@ public class ArrayGenTest extends CodegenTestCase {
public void testIntGenerics () throws Exception { public void testIntGenerics () throws Exception {
loadText("class L<T>(var a : T) {} fun foo() = L<Int>(5).a"); loadText("class L<T>(var a : T) {} fun foo() = L<Int>(5).a");
// System.out.println(generateToText()); System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
Object invoke = foo.invoke(null); Object invoke = foo.invoke(null);
System.out.println(invoke.getClass()); System.out.println(invoke.getClass());