diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index ac773ff6e98..f3672f92bcf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -168,9 +168,9 @@ public class AsmUtil { return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes)); } - public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { - return (functionDescriptor.getModality() == Modality.ABSTRACT - || isJvmInterface(functionDescriptor.getContainingDeclaration())) + public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) { + return (functionDescriptor.getModality() == Modality.ABSTRACT || + (isJvmInterface(functionDescriptor.getContainingDeclaration()) && !state.isJvm8Target())) && !isStaticMethod(kind, functionDescriptor); } @@ -184,7 +184,7 @@ public class AsmUtil { return kind == OwnerKind.PACKAGE || kind == OwnerKind.DEFAULT_IMPLS; } - public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { + public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) { int flags = getCommonCallableFlags(functionDescriptor); for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) { @@ -214,7 +214,7 @@ public class AsmUtil { flags |= ACC_STATIC; } - if (isAbstractMethod(functionDescriptor, kind)) { + if (isAbstractMethod(functionDescriptor, kind, state)) { flags |= ACC_ABSTRACT; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 2728c646c83..d06a75c199f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -63,10 +63,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; -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.*; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; @@ -163,7 +160,7 @@ public class FunctionCodegen { JvmMethodGenericSignature jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, contextKind); Method asmMethod = jvmSignature.getAsmMethod(); - int flags = getMethodAsmFlags(functionDescriptor, contextKind); + int flags = getMethodAsmFlags(functionDescriptor, contextKind, state); if (origin.getOriginKind() == JvmDeclarationOriginKind.SAM_DELEGATION) { flags |= ACC_SYNTHETIC; @@ -198,7 +195,7 @@ public class FunctionCodegen { parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen)); } - if (state.getClassBuilderMode() != ClassBuilderMode.FULL || isAbstractMethod(functionDescriptor, contextKind)) { + if (state.getClassBuilderMode() != ClassBuilderMode.FULL || isAbstractMethod(functionDescriptor, contextKind, state)) { generateLocalVariableTable( mv, jvmSignature, @@ -356,6 +353,15 @@ public class FunctionCodegen { generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext()); methodEnd = new Label(); } + else if (OwnerKind.IMPLEMENTATION == context.getContextKind() && + JvmCodegenUtil.isJvmInterface(functionDescriptor.getContainingDeclaration())) { + int flags = AsmUtil.getMethodAsmFlags(functionDescriptor, OwnerKind.IMPLEMENTATION, context.getState()); + assert (flags & Opcodes.ACC_ABSTRACT) == 0 : "Interface method with body should be non-abstract" + functionDescriptor; + Type type = typeMapper.mapDefaultImpls((ClassDescriptor) functionDescriptor.getContainingDeclaration()); + Method asmMethod = typeMapper.mapAsmMethod(functionDescriptor, OwnerKind.DEFAULT_IMPLS); + generateDelegateToMethodBody(true, mv, asmMethod, type.getInternalName()); + methodEnd = new Label(); + } else { FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), functionDescriptor)); @@ -600,7 +606,7 @@ public class FunctionCodegen { } } - if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) { + if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION, state)) { CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor); assert overridden != null; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 34894b65911..675b41c3fc9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -310,7 +310,7 @@ public class InlineCodegen extends CallGenerator { MethodNode node = new MethodNode( InlineCodegenUtil.API, - getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), + getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0), asmMethod.getName(), asmMethod.getDescriptor(), null, null @@ -474,7 +474,7 @@ public class InlineCodegen extends CallGenerator { JvmMethodSignature jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(descriptor); Method asmMethod = jvmMethodSignature.getAsmMethod(); MethodNode methodNode = new MethodNode( - InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), + InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind(), state), asmMethod.getName(), asmMethod.getDescriptor(), null, null ); @@ -678,7 +678,7 @@ public class InlineCodegen extends CallGenerator { @Override public void putHiddenParams() { - if ((getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == 0) { + if ((getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) & Opcodes.ACC_STATIC) == 0) { invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false); } diff --git a/compiler/testData/codegen/java8/writeFlags/defaultMethod.kt b/compiler/testData/codegen/java8/writeFlags/defaultMethod.kt new file mode 100644 index 00000000000..2458a71330b --- /dev/null +++ b/compiler/testData/codegen/java8/writeFlags/defaultMethod.kt @@ -0,0 +1,16 @@ +// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET +interface Test { + fun test(): String { + return "OK" + } + + fun testAbstract(): String +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Test, test +// FLAGS: ACC_PUBLIC + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Test, testAbstract +// FLAGS: ACC_PUBLIC, ACC_ABSTRACT \ No newline at end of file diff --git a/compiler/testData/codegen/java8/writeFlags/interfaceAndDefaultImpls.kt b/compiler/testData/codegen/java8/writeFlags/interfaceAndDefaultImpls.kt new file mode 100644 index 00000000000..3e38b83e06a --- /dev/null +++ b/compiler/testData/codegen/java8/writeFlags/interfaceAndDefaultImpls.kt @@ -0,0 +1,15 @@ +// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET +interface Test { + fun a() { + + } +} + +// TESTED_OBJECT_KIND: class +// TESTED_OBJECTS: Test$DefaultImpls +// FLAGS: ACC_PUBLIC, ACC_FINAL, ACC_SUPER + + +// TESTED_OBJECT_KIND: class +// TESTED_OBJECTS: Test +// FLAGS: ACC_PUBLIC, ACC_ABSTRACT, ACC_INTERFACE diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java new file mode 100644 index 00000000000..3ecef9d7b5a --- /dev/null +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2016 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.kotlin.codegen.flags; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/codegen/java8/writeFlags") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest { + public void testAllFilesPresentInWriteFlags() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/writeFlags"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("defaultMethod.kt") + public void testDefaultMethod() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/writeFlags/defaultMethod.kt"); + doTest(fileName); + } + + @TestMetadata("interfaceAndDefaultImpls.kt") + public void testInterfaceAndDefaultImpls() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/writeFlags/interfaceAndDefaultImpls.kt"); + doTest(fileName); + } +}