diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index f13b283d1fd..d3ee9971ca5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -106,7 +106,11 @@ public abstract class CodegenContext { } public CodegenContext intoNamespace(NamespaceDescriptor descriptor) { - return new CodegenContexts.NamespaceContext(descriptor, this); + return new CodegenContexts.NamespaceContext(descriptor, this, null); + } + + public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor) { + return new CodegenContexts.NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(StackValue.none(), delegateTo)); } public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java index 61065e89de3..5250cbbbc73 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java @@ -272,8 +272,8 @@ public class CodegenContexts { } public static class NamespaceContext extends CodegenContext { - public NamespaceContext(NamespaceDescriptor contextDescriptor, CodegenContext parent) { - super(contextDescriptor, OwnerKind.NAMESPACE, parent, null); + public NamespaceContext(NamespaceDescriptor contextDescriptor, CodegenContext parent, OwnerKind kind) { + super(contextDescriptor, kind != null ? kind : OwnerKind.NAMESPACE, parent, null); } @Override diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 198c87ffe52..83f977d0004 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -113,7 +113,7 @@ public class FunctionCodegen { ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) { - boolean isStatic = kind == OwnerKind.NAMESPACE; + boolean isStatic = kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind; if (isStatic || kind == OwnerKind.TRAIT_IMPL) flags |= ACC_STATIC; @@ -199,13 +199,24 @@ public class FunctionCodegen { frameMap.enter(parameter, argTypes[i+add].getSize()); } - if ((kind instanceof OwnerKind.DelegateKind) != (functionDescriptor.getKind() == FunctionDescriptor.Kind.DELEGATION)) { + if (!isStatic && (kind instanceof OwnerKind.DelegateKind) != (functionDescriptor.getKind() == FunctionDescriptor.Kind.DELEGATION)) { throw new IllegalStateException("mismatching kind in " + functionDescriptor); } Map mapLabelsToDivideLocalVarVisibilityForSharedVar = new HashMap(); - if (kind instanceof OwnerKind.DelegateKind) { + if (kind instanceof OwnerKind.StaticDelegateKind) { + OwnerKind.StaticDelegateKind dk = (OwnerKind.StaticDelegateKind) kind; + InstructionAdapter iv = new InstructionAdapter(mv); + for (int i = 0, k = 0; i < argTypes.length; i++) { + Type argType = argTypes[i]; + iv.load(k, argType); + k += argType.getSize(); + } + iv.invokestatic(dk.getOwnerClass(), jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor()); + iv.areturn(jvmSignature.getAsmMethod().getReturnType()); + } + else if (kind instanceof OwnerKind.DelegateKind) { OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; InstructionAdapter iv = new InstructionAdapter(mv); iv.load(0, JetTypeMapper.TYPE_OBJECT); @@ -355,7 +366,7 @@ public class FunctionCodegen { if(needed) { ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); boolean hasReceiver = receiverParameter.exists(); - boolean isStatic = kind == OwnerKind.NAMESPACE; + boolean isStatic = kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind; if(kind == OwnerKind.TRAIT_IMPL) { String correctedDescr = "(" + jvmSignature.getDescriptor().substring(jvmSignature.getDescriptor().indexOf(";") + 1); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 1eb2c992634..c2f01371176 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -110,6 +110,10 @@ public class GenerationState { return getFactory().newVisitor(getInjector().getJetTypeMapper().mapType(aClass.getDefaultType(), MapTypeMode.IMPL).getInternalName() + ".class"); } + public ClassBuilder forNamespacepart(String name, JetFile file) { + return getFactory().newVisitor(name + ".class"); + } + public ClassBuilder forTraitImplementation(ClassDescriptor aClass) { return getFactory().newVisitor(getInjector().getJetTypeMapper().mapType(aClass.getDefaultType(), MapTypeMode.TRAIT_IMPL).getInternalName() + ".class"); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 25364fcc159..96bda0ab3c2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -176,7 +176,7 @@ public class JetTypeMapper { } public static MapTypeMode ownerKindToMapTypeMode(OwnerKind kind) { - if (kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.NAMESPACE) { + if (kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind) { return MapTypeMode.IMPL; } else if (kind == OwnerKind.TRAIT_IMPL) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index daff7dbafbf..111da30ecd5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; @@ -34,6 +35,7 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; +import java.util.ArrayList; import java.util.Collection; import static org.objectweb.asm.Opcodes.*; @@ -46,6 +48,7 @@ public class NamespaceCodegen { @NotNull private final FqName name; private final GenerationState state; private final Collection files; + private int nextMultiFile = 0; public NamespaceCodegen(ClassBuilder v, @NotNull FqName fqName, GenerationState state, Collection files) { this.v = v; @@ -67,12 +70,27 @@ public class NamespaceCodegen { } public void generate(CompilationErrorHandler errorHandler, Progress progress) { + ArrayList>> byFile = new ArrayList>>(); + + for (JetFile file : files) { + ArrayList fileFunctions = new ArrayList(); + for (JetDeclaration declaration : file.getDeclarations()) { + if (declaration instanceof JetNamedFunction) { + fileFunctions.add(declaration); + } + } + if(fileFunctions.size() > 0) + byFile.add(new Pair>(file, fileFunctions)); + } + + boolean multiFile = byFile.size() > 1; + 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); + generate(file, multiFile); } catch (ProcessCanceledException e) { throw e; @@ -91,14 +109,22 @@ public class NamespaceCodegen { } } - private void generate(JetFile file) { + private void generate(JetFile file, boolean multiFile) { for (JetDeclaration declaration : file.getDeclarations()) { - if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) { + if (declaration instanceof JetProperty) { NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor); state.getInjector().getMemberCodegen().generateFunctionOrProperty( (JetTypeParameterListOwner) declaration, context, v); } + else if (declaration instanceof JetNamedFunction) { + if(!multiFile) { + NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); + final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor); + state.getInjector().getMemberCodegen().generateFunctionOrProperty( + (JetTypeParameterListOwner) declaration, context, v); + } + } else if (declaration instanceof JetClassOrObject) { NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor); @@ -108,6 +134,47 @@ public class NamespaceCodegen { state.getInjector().getScriptCodegen().generate((JetScript) declaration); } } + + if(multiFile) { + int k = 0; + for (JetDeclaration declaration : file.getDeclarations()) { + if (declaration instanceof JetNamedFunction) { + k++; + } + } + + if(k > 0) { + PsiFile containingFile = file.getContainingFile(); + String className = name.getFqName().replace('.','/') + "namespace$src$" + (nextMultiFile++); + ClassBuilder builder = state.forNamespacepart(className, file); + + builder.defineClass(containingFile, V1_6, + ACC_PUBLIC/*|ACC_SUPER*/, + className, + null, + //"jet/lang/Namespace", + "java/lang/Object", + new String[0] + ); + builder.visitSource(containingFile.getName(), null); + + for (JetDeclaration declaration : file.getDeclarations()) { + if (declaration instanceof JetNamedFunction) { + NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); + { + final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor); + state.getInjector().getMemberCodegen().generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, builder); + } + { + final CodegenContext context = CodegenContexts.STATIC.intoNamespacePart(className, descriptor); + state.getInjector().getMemberCodegen().generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v); + } + } + } + + builder.done(); + } + } } private void generateStaticInitializers() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/OwnerKind.java b/compiler/backend/src/org/jetbrains/jet/codegen/OwnerKind.java index 21d556dbad5..85686c55086 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/OwnerKind.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/OwnerKind.java @@ -49,6 +49,25 @@ public class OwnerKind { } } + public static class StaticDelegateKind extends OwnerKind { + private final StackValue delegate; + private final String ownerClass; + + public StaticDelegateKind(StackValue delegate, String ownerClass) { + super("staticDelegateKind"); + this.delegate = delegate; + this.ownerClass = ownerClass; + } + + public StackValue getDelegate() { + return delegate; + } + + public String getOwnerClass() { + return ownerClass; + } + } + @Override public String toString() { return "OwnerKind(" + name + ")"; diff --git a/compiler/testData/codegen/multi/simple/ok.kt b/compiler/testData/codegen/multi/simple/ok.kt index 654494514f0..d8b5fb5b66a 100644 --- a/compiler/testData/codegen/multi/simple/ok.kt +++ b/compiler/testData/codegen/multi/simple/ok.kt @@ -1 +1 @@ -fun ok() = "OK" \ No newline at end of file +fun ok(res: String = "OK") = res \ No newline at end of file