From 177b3eae5ec492467e7ae68d9e92cf61b51bc8f4 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 8 Jun 2012 04:19:23 +0400 Subject: [PATCH] do not generate namespace class for empty namespace --- .../jet/codegen/ClassBuilderOnDemand.java | 63 ++++++++++++ .../jet/codegen/ClassFileFactory.java | 12 ++- .../jet/codegen/NamespaceCodegen.java | 95 +++++++++++-------- 3 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java new file mode 100644 index 00000000000..c0dc194eafb --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Stepan Koltsov + */ +public abstract class ClassBuilderOnDemand { + + private ClassBuilder classBuilder; + + private List optionalDeclarations = Lists.newArrayList(); + + interface ClassBuilderCallback { + void doSomething(@NotNull ClassBuilder classBuilder); + } + + @NotNull + protected abstract ClassBuilder createClassBuilder(); + + public void addOptionalDeclaration(@NotNull ClassBuilderCallback callback) { + optionalDeclarations.add(callback); + if (classBuilder != null) { + callback.doSomething(classBuilder); + } + } + + @NotNull + public ClassBuilder getClassBuilder() { + if (classBuilder == null) { + classBuilder = createClassBuilder(); + for (ClassBuilderCallback callback : optionalDeclarations) { + callback.doSomething(classBuilder); + } + } + return classBuilder; + } + + public void done() { + if (classBuilder != null) { + classBuilder.done(); + } + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java index ceeb75b3882..b0226da2533 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -61,12 +61,18 @@ public class ClassFileFactory { return newVisitor(className.getInternalName() + ".class"); } - NamespaceCodegen forNamespace(FqName fqName, Collection files) { + NamespaceCodegen forNamespace(final FqName fqName, Collection files) { assert !isDone : "Already done!"; NamespaceCodegen codegen = ns2codegen.get(fqName); if (codegen == null) { - final ClassBuilder builder = newVisitor(NamespaceCodegen.getJVMClassNameForKotlinNs(fqName).getInternalName() + ".class"); - codegen = new NamespaceCodegen(builder, fqName, state, files); + ClassBuilderOnDemand onDemand = new ClassBuilderOnDemand() { + @NotNull + @Override + protected ClassBuilder createClassBuilder() { + return newVisitor(NamespaceCodegen.getJVMClassNameForKotlinNs(fqName).getInternalName() + ".class"); + } + }; + codegen = new NamespaceCodegen(onDemand, fqName, state, files); ns2codegen.put(fqName, codegen); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 111da30ecd5..2c1511f92b2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -44,29 +44,37 @@ import static org.objectweb.asm.Opcodes.*; * @author max */ public class NamespaceCodegen { - private final ClassBuilder v; + @NotNull + private final ClassBuilderOnDemand v; @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) { + public NamespaceCodegen(@NotNull ClassBuilderOnDemand v, @NotNull final FqName fqName, GenerationState state, Collection files) { this.v = v; name = fqName; this.state = state; this.files = files; - PsiFile sourceFile = files.iterator().next().getContainingFile(); - v.defineClass(sourceFile, V1_6, - ACC_PUBLIC/*|ACC_SUPER*/, - getJVMClassNameForKotlinNs(fqName).getInternalName(), - null, - //"jet/lang/Namespace", - "java/lang/Object", - new String[0] - ); - // TODO figure something out for a namespace that spans multiple files - v.visitSource(sourceFile.getName(), null); + final PsiFile sourceFile = files.iterator().next().getContainingFile(); + + v.addOptionalDeclaration(new ClassBuilderOnDemand.ClassBuilderCallback() { + @Override + public void doSomething(@NotNull ClassBuilder v) { + v.defineClass(sourceFile, V1_6, + ACC_PUBLIC/*|ACC_SUPER*/, + getJVMClassNameForKotlinNs(fqName).getInternalName(), + null, + //"jet/lang/Namespace", + "java/lang/Object", + new String[0] + ); + // TODO figure something out for a namespace that spans multiple files + v.visitSource(sourceFile.getName(), null); + } + }); + } public void generate(CompilationErrorHandler errorHandler, Progress progress) { @@ -115,14 +123,14 @@ public class NamespaceCodegen { 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); + (JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); } 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); + (JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); } } else if (declaration instanceof JetClassOrObject) { @@ -167,7 +175,7 @@ public class NamespaceCodegen { } { final CodegenContext context = CodegenContexts.STATIC.intoNamespacePart(className, descriptor); - state.getInjector().getMemberCodegen().generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v); + state.getInjector().getMemberCodegen().generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); } } } @@ -178,39 +186,44 @@ public class NamespaceCodegen { } private void generateStaticInitializers() { - JetFile namespace = files.iterator().next(); // @todo: hack + final JetFile namespace = files.iterator().next(); // @todo: hack - MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); - for (JetFile file : files) { - if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { - mv.visitCode(); + v.addOptionalDeclaration(new ClassBuilderOnDemand.ClassBuilderCallback() { + @Override + public void doSomething(@NotNull ClassBuilder v) { + MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); + for (JetFile file : files) { + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + mv.visitCode(); - FrameMap frameMap = new FrameMap(); - ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state); + FrameMap frameMap = new FrameMap(); + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state); - for (JetDeclaration declaration : file.getDeclarations()) { - if (declaration instanceof JetProperty) { - final JetExpression initializer = ((JetProperty) declaration).getInitializer(); - if (initializer != null && !(initializer instanceof JetConstantExpression)) { - final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration); - assert descriptor != null; - if(descriptor.getReceiverParameter().exists()) { - continue; + for (JetDeclaration declaration : file.getDeclarations()) { + if (declaration instanceof JetProperty) { + final JetExpression initializer = ((JetProperty) declaration).getInitializer(); + if (initializer != null && !(initializer instanceof JetConstantExpression)) { + final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration); + assert descriptor != null; + if(descriptor.getReceiverParameter().exists()) { + continue; + } + codegen.genToJVMStack(initializer); + StackValue.Property propValue = codegen.intermediateValueForProperty(descriptor, true, null); + propValue.store(propValue.type, new InstructionAdapter(mv)); + } } - codegen.genToJVMStack(initializer); - StackValue.Property propValue = codegen.intermediateValueForProperty(descriptor, true, null); - propValue.store(propValue.type, new InstructionAdapter(mv)); } } } - } - } - if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { - mv.visitInsn(RETURN); - FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace); - mv.visitEnd(); - } + if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + mv.visitInsn(RETURN); + FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace); + mv.visitEnd(); + } + } + }); } private boolean hasNonConstantPropertyInitializers() {