diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index f4dea369179..0a855871113 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -22,11 +22,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.org.objectweb.asm.AnnotationVisitor; -import org.jetbrains.org.objectweb.asm.Label; -import org.jetbrains.org.objectweb.asm.MethodVisitor; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapper; @@ -39,19 +34,24 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.org.objectweb.asm.AnnotationVisitor; +import org.jetbrains.org.objectweb.asm.Label; +import org.jetbrains.org.objectweb.asm.MethodVisitor; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; -import static org.jetbrains.org.objectweb.asm.Opcodes.*; import static org.jetbrains.jet.codegen.JvmCodegenUtil.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive; +import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class AsmUtil { private static final Set PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet( @@ -214,6 +214,24 @@ public class AsmUtil { return NO_FLAG_PACKAGE_PRIVATE; } + + public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) { + if (isDeclarationInsideInlineFunction(descriptor)) { + return ACC_PUBLIC; + } + return NO_FLAG_PACKAGE_PRIVATE; + } + + public static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) { + //NB: constructor context couldn't be inline + DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration(); + if (parentDeclaration instanceof SimpleFunctionDescriptor && + ((SimpleFunctionDescriptor) parentDeclaration).getInlineStrategy().isInline()) { + return true; + } + return false; + } + public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { if (descriptor instanceof PropertyAccessorDescriptor) { return KotlinBuiltIns.getInstance().isDeprecated(descriptor) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index c88e4970746..4156f9c3588 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -24,7 +24,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.LocalLookup; -import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.state.GenerationState; @@ -92,12 +91,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { this.asmType = asmTypeForAnonymousClass(bindingContext, funDescriptor); - //TODO: We should write header on lambda class and filter all completions by header - if (parentContext instanceof MethodContext) { - visibilityFlag = ((MethodContext) parentContext).isInlineFunction() ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE; - } else { - visibilityFlag = NO_FLAG_PACKAGE_PRIVATE; - } + visibilityFlag = AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor); } public void gen() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 81d4d42ea87..ab38c12a3ca 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -248,15 +248,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { // Do not emit enclosing method in "light-classes mode" since currently we generate local light classes as if they're top level if (isLocalOrAnonymousClass && state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) { String outerClassName = getOuterClassName(descriptor, typeMapper); - FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class); + FunctionDescriptor function = AsmUtil.isDeclarationInsideInlineFunction(descriptor) + ? null + : DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class); if (function != null) { Method method = typeMapper.mapSignature(function).getAsmMethod(); v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor()); } else { - assert isObjectLiteral - : "Function descriptor could be null only for object literal in package: " + descriptor.getName(); v.visitOuterClass(outerClassName, null, null); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index 07b00118b38..72e81330396 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -346,4 +346,8 @@ public abstract class MemberCodegen methodsToTransform = new ArrayList(); reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { + @Override + public void visitOuterClass(@NotNull String owner, String name, String desc) { + InliningContext parent = inliningContext.getParent(); + assert parent != null : "Context for transformer should have parent one: " + inliningContext; + + //we don't write owner info for lamdbas and SAMs just only for objects + if (parent.isRoot() || parent.isInliningLambdaRootContext()) { + //TODO: think about writing method info - there is some problem with new constructor desc calculation + super.visitOuterClass(inliningContext.getParent().getClassNameToInline(), null, null); + return; + } + + super.visitOuterClass(owner, name, desc); + } + @Override public MethodVisitor visitMethod( int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions @@ -267,7 +282,7 @@ public class AnonymousObjectTransformer { @NotNull private ClassBuilder createClassBuilder() { - return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, inliningContext.call.getCallElement().getContainingFile()), + return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, inliningContext.getRoot().call.getCallElement().getContainingFile()), new TypeRemapper(inliningContext.typeMapping)); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java index 4ceff1213ed..e8fc192bd8a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -196,10 +196,13 @@ public class InlineCodegen implements CallGenerator { Parameters parameters = new Parameters(realParams, Parameters.shiftAndAddStubs(captured, realParams.size())); - InliningContext info = - new InliningContext(expressionMap, null, null, null, state, - codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), - codegen.getContext(), call, Collections.emptyMap(), false, false); + InliningContext info = new RootInliningContext(expressionMap, + state, + codegen.getInlineNameGenerator() + .subGenerator(functionDescriptor.getName().asString()), + codegen.getContext(), + call, + codegen.getParentCodegen().getClassName()); MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + call.getCallElement().getText()); //with captured diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java index bcf43a1f433..ef85eaf942a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java @@ -16,60 +16,44 @@ package org.jetbrains.jet.codegen.inline; -import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.state.GenerationState; -import org.jetbrains.jet.lang.psi.Call; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; public class InliningContext { + @Nullable + private final InliningContext parent; + public final Map expressionMap; - public final List invokeCalls; - - public final List constructorInvocation; - - public final LocalVarRemapper remapper; - public final GenerationState state; public final NameGenerator nameGenerator; - public final CodegenContext startContext; - - public final Call call; - public final Map typeMapping; public final boolean isInliningLambda; public final boolean classRegeneration; - public InliningContext( - Map map, - List accesses, - List invocation, - LocalVarRemapper remapper, - GenerationState state, - NameGenerator nameGenerator, - CodegenContext startContext, - Call call, - Map typeMapping, + protected InliningContext( + @Nullable InliningContext parent, + @NotNull Map map, + @NotNull GenerationState state, + @NotNull NameGenerator nameGenerator, + @NotNull Map typeMapping, boolean isInliningLambda, boolean classRegeneration ) { + this.parent = parent; expressionMap = map; - invokeCalls = accesses; - constructorInvocation = invocation; - this.remapper = remapper; this.state = state; this.nameGenerator = nameGenerator; - this.startContext = startContext; - this.call = call; this.typeMapping = typeMapping; this.isInliningLambda = isInliningLambda; this.classRegeneration = classRegeneration; @@ -80,7 +64,7 @@ public class InliningContext { } public InliningContext subInlineLambda(LambdaInfo lambdaInfo) { - Map map = new HashMap(); + Map map = new HashMap(); map.put(lambdaInfo.getLambdaClassType().getInternalName(), null); //mark lambda inlined return subInline(nameGenerator.subGenerator("lambda"), map, true); } @@ -89,15 +73,58 @@ public class InliningContext { return subInline(generator, additionalTypeMappings, isInliningLambda); } - public InliningContext subInline(NameGenerator generator, Map additionalTypeMappings, boolean isInliningLambda) { + public InliningContext subInlineWithClassRegeneration(@NotNull NameGenerator generator, + @NotNull Map additionalTypeMappings, + @NotNull ConstructorInvocation constructorInvocation) { Map newTypeMappings = new HashMap(typeMapping); newTypeMappings.putAll(additionalTypeMappings); - return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call, - newTypeMappings, isInliningLambda, classRegeneration); + return new RegenetedClassContext(this, expressionMap, state, generator, + newTypeMappings, isInliningLambda, constructorInvocation); + } - public InliningContext classRegeneration() { - return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, nameGenerator, startContext, call, - typeMapping, isInliningLambda, true); + public InliningContext subInline(NameGenerator generator, Map additionalTypeMappings, boolean isInliningLambda) { + return subInline(generator, additionalTypeMappings, isInliningLambda, classRegeneration); + } + + private InliningContext subInline( + NameGenerator generator, + Map additionalTypeMappings, + boolean isInliningLambda, + boolean isRegeneration + ) { + Map newTypeMappings = new HashMap(typeMapping); + newTypeMappings.putAll(additionalTypeMappings); + return new InliningContext(this, expressionMap, state, generator, + newTypeMappings, isInliningLambda, isRegeneration); + } + + public boolean isRoot() { + return parent == null; + } + + @NotNull + public RootInliningContext getRoot() { + if (isRoot()) { + return (RootInliningContext) this; + } + else { + return parent.getRoot(); + } + } + + @Nullable + public InliningContext getParent() { + return parent; + } + + public boolean isInliningLambdaRootContext() { + //noinspection ConstantConditions + return isInliningLambda && !getParent().isInliningLambda; + } + + public String getClassNameToInline() { + assert parent != null : "At least root context should return proper value"; + return parent.getClassNameToInline(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java index 778959db44b..cc5df6c4186 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -141,9 +141,15 @@ public class MethodInliner { //TODO: need poping of type but what to do with local funs??? Type newLambdaType = Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName()); currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName()); - AnonymousObjectTransformer transformer = new AnonymousObjectTransformer(invocation.getOwnerInternalName(), - inliningContext.subInline(inliningContext.nameGenerator, currentTypeMapping).classRegeneration(), - isSameModule, newLambdaType); + AnonymousObjectTransformer transformer = + new AnonymousObjectTransformer(invocation.getOwnerInternalName(), + inliningContext + .subInlineWithClassRegeneration( + inliningContext.nameGenerator, + currentTypeMapping, + invocation), + isSameModule, newLambdaType + ); InlineResult transformResult = transformer.doTransform(invocation, nodeRemapper); result.addAllClassesToRemove(transformResult); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java new file mode 100644 index 00000000000..98c231a9e08 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2014 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.inline; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.state.GenerationState; + +import java.util.Map; + +public class RegenetedClassContext extends InliningContext { + + @NotNull + private final ConstructorInvocation constructorInvocation; + + protected RegenetedClassContext( + @Nullable InliningContext parent, + @NotNull Map map, + @NotNull GenerationState state, + @NotNull NameGenerator nameGenerator, + @NotNull Map typeMapping, + boolean isInliningLambda, + @NotNull ConstructorInvocation constructorInvocation + ) { + super(parent, map, state, nameGenerator, typeMapping, isInliningLambda, true); + this.constructorInvocation = constructorInvocation; + } + + @Override + public String getClassNameToInline() { + return constructorInvocation.getOwnerInternalName(); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java new file mode 100644 index 00000000000..aecea68d782 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2014 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.inline; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.state.GenerationState; +import org.jetbrains.jet.lang.psi.Call; + +import java.util.Collections; +import java.util.Map; + +public class RootInliningContext extends InliningContext { + + public final CodegenContext startContext; + + @NotNull + private final String classNameToInline; + + public final Call call; + + public RootInliningContext( + @NotNull Map map, + @NotNull GenerationState state, + @NotNull NameGenerator nameGenerator, + @NotNull CodegenContext startContext, + @NotNull Call call, + @NotNull String classNameToInline + ) { + super(null, map, state, nameGenerator, Collections.emptyMap(), false, false); + this.call = call; + this.startContext = startContext; + this.classNameToInline = classNameToInline; + } + + @Override + public boolean isRoot() { + return true; + } + + @NotNull + public String getClassNameToInline() { + return classNameToInline; + } +}