Fix for KT-11590: IllegalAccessError: SAM adapter generated with invalid accessibility for inline function

#KT-11590 Fixed
This commit is contained in:
Michael Bogdanov
2016-03-24 10:31:45 +01:00
parent 33cd661aad
commit d0aac74e72
10 changed files with 133 additions and 54 deletions
@@ -2317,7 +2317,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
final Type asmType =
state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), getParentCodegen());
state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this);
return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
@Override
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2015 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;
import com.google.common.collect.Maps;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.Map;
public class SamWrapperClasses {
private final GenerationState state;
private final Map<Pair<SamType, KtFile>, Type> samInterfaceToWrapperClass = Maps.newHashMap();
public SamWrapperClasses(@NotNull GenerationState state) {
this.state = state;
}
@NotNull
public Type getSamWrapperClass(@NotNull final SamType samType, @NotNull final KtFile file, @NotNull final MemberCodegen<?> parentCodegen) {
return ContainerUtil.getOrCreate(samInterfaceToWrapperClass, Pair.create(samType, file),
new Factory<Type>() {
@Override
public Type create() {
return new SamWrapperCodegen(state, samType, parentCodegen).genWrapper(file);
}
});
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2015 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
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.org.objectweb.asm.Type
class SamWrapperClasses(private val state: GenerationState) {
private data class WrapperKey(val samType: SamType, val file: KtFile, val insideInline: Boolean)
private val samInterfaceToWrapperClass = hashMapOf<WrapperKey, Type>()
fun getSamWrapperClass(samType: SamType, file: KtFile, expressionCodegen: ExpressionCodegen): Type {
val isInsideInline = InlineUtil.isInlineOrContainingInline(expressionCodegen.context.contextDescriptor)
return samInterfaceToWrapperClass.getOrPut(WrapperKey(samType, file, isInsideInline)) {
SamWrapperCodegen(state, samType, expressionCodegen.parentCodegen, isInsideInline).genWrapper(file)
}
}
}
@@ -49,17 +49,27 @@ public class SamWrapperCodegen {
private static final String FUNCTION_FIELD_NAME = "function";
private final GenerationState state;
private final boolean isInsideInline;
private final KotlinTypeMapper typeMapper;
private final SamType samType;
private final MemberCodegen<?> parentCodegen;
private final int visibility;
public SamWrapperCodegen(@NotNull GenerationState state, @NotNull SamType samType, @NotNull MemberCodegen<?> parentCodegen) {
public SamWrapperCodegen(
@NotNull GenerationState state,
@NotNull SamType samType,
@NotNull MemberCodegen<?> parentCodegen,
boolean isInsideInline
) {
this.state = state;
this.isInsideInline = isInsideInline;
this.typeMapper = state.getTypeMapper();
this.samType = samType;
this.parentCodegen = parentCodegen;
visibility = isInsideInline ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
}
@NotNull
public Type genWrapper(@NotNull KtFile file) {
// Name for generated class, in form of whatever$1
FqName fqName = getWrapperName(file);
@@ -88,7 +98,7 @@ public class SamWrapperCodegen {
ClassBuilder cv = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(erasedInterfaceFunction), asmType, file);
cv.defineClass(file,
V1_6,
ACC_FINAL | ACC_SUPER,
ACC_FINAL | ACC_SUPER | visibility,
asmType.getInternalName(),
null,
OBJECT_TYPE.getInternalName(),
@@ -118,7 +128,7 @@ public class SamWrapperCodegen {
private void generateConstructor(Type ownerType, Type functionType, ClassBuilder cv) {
MethodVisitor mv = cv.newMethod(JvmDeclarationOriginKt.OtherOrigin(samType.getJavaClassDescriptor()),
NO_FLAG_PACKAGE_PRIVATE, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
visibility, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
@@ -177,9 +187,10 @@ public class SamWrapperCodegen {
int hash = PackagePartClassUtils.getPathHashCode(containingFile.getVirtualFile()) * 31 +
DescriptorUtils.getFqNameSafe(descriptor).hashCode();
String shortName = String.format(
"%s$sam$%s$%08x",
"%s$sam$%s%s$%08x",
fileClassFqName.shortName().asString(),
descriptor.getName().asString(),
(isInsideInline ? "$i" : ""),
hash
);
return fileClassFqName.parent().child(Name.identifier(shortName));
@@ -0,0 +1,19 @@
// FILE: 1.kt
package test
inline fun <reified T> makeRunnable(noinline lambda: ()->Unit) : Runnable {
return Runnable(lambda)
}
// FILE: 2.kt
import test.*
fun box(): String {
var result = "fail"
makeRunnable<String> { result = "OK" }.run()
return result
}
@@ -0,0 +1,23 @@
package test
inline fun <reified T> makeRunnable(noinline lambda: ()->Unit) : Runnable {
return Runnable(lambda)
}
inline fun makeRunnable2(noinline lambda: ()->Unit) : Runnable {
return Runnable(lambda)
}
fun noInline(lambda: ()->Unit) : Runnable {
return Runnable(lambda)
}
fun noInline2(lambda: ()->Unit) : Runnable {
return Runnable(lambda)
}
// 1 final class test/_1Kt\$sam\$Runnable\$89f9321c
// 1 public final class test/_1Kt\$sam\$Runnable\$i\$89f9321c
// 2 class test/_1Kt\$sam\$
@@ -0,0 +1,21 @@
@kotlin.Metadata
final class test/SamAdapterAndInlinedOneKt$sam$Runnable$82391ccd {
private synthetic final field function: kotlin.jvm.functions.Function0
method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic final method run(): void
}
@kotlin.Metadata
public final class test/SamAdapterAndInlinedOneKt$sam$Runnable$i$82391ccd {
private synthetic final field function: kotlin.jvm.functions.Function0
public method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic final method run(): void
}
@kotlin.Metadata
public final class test/SamAdapterAndInlinedOneKt {
private final static method makeRunnable(p0: kotlin.jvm.functions.Function0): java.lang.Runnable
public final static @org.jetbrains.annotations.NotNull method makeRunnable2(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Runnable
public final static @org.jetbrains.annotations.NotNull method noInline(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Runnable
public final static @org.jetbrains.annotations.NotNull method noInline2(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Runnable
}
@@ -175,6 +175,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
doTest(fileName);
}
@TestMetadata("sam.kt")
public void testSam() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -59,6 +59,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
doTest(fileName);
}
@TestMetadata("samAdapterAndInlinedOne.kt")
public void testSamAdapterAndInlinedOne() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/samAdapterAndInlinedOne.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -175,6 +175,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
doTest(fileName);
}
@TestMetadata("sam.kt")
public void testSam() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)