Support transient, strictfp and synchronized flags
#KT-4377 Fixed
This commit is contained in:
@@ -19,7 +19,6 @@ package org.jetbrains.jet.codegen;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
|
||||
@@ -30,7 +29,6 @@ import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.lang.psi.JetModifierList;
|
||||
import org.jetbrains.jet.lang.psi.JetModifierListOwner;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
||||
@@ -38,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -46,7 +45,34 @@ import java.util.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
|
||||
|
||||
public abstract class AnnotationCodegen {
|
||||
public static final FqName VOLATILE_FQ_NAME = new FqName("kotlin.volatile");
|
||||
|
||||
public static final class JvmFlagAnnotation {
|
||||
private final FqName fqName;
|
||||
private final int jvmFlag;
|
||||
|
||||
public JvmFlagAnnotation(@NotNull String fqName, int jvmFlag) {
|
||||
this.fqName = new FqName(fqName);
|
||||
this.jvmFlag = jvmFlag;
|
||||
}
|
||||
|
||||
public boolean hasAnnotation(@NotNull Annotated annotated) {
|
||||
return annotated.getAnnotations().findAnnotation(fqName) != null;
|
||||
}
|
||||
|
||||
public int getJvmFlag() {
|
||||
return jvmFlag;
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<JvmFlagAnnotation> FIELD_FLAGS = Arrays.asList(
|
||||
new JvmFlagAnnotation("kotlin.jvm.volatile", Opcodes.ACC_VOLATILE),
|
||||
new JvmFlagAnnotation("kotlin.jvm.transient", Opcodes.ACC_TRANSIENT)
|
||||
);
|
||||
|
||||
public static final List<JvmFlagAnnotation> METHOD_FLAGS = Arrays.asList(
|
||||
new JvmFlagAnnotation("kotlin.jvm.strictfp", Opcodes.ACC_STRICT),
|
||||
new JvmFlagAnnotation("kotlin.jvm.synchronized", Opcodes.ACC_SYNCHRONIZED)
|
||||
);
|
||||
|
||||
private static final AnnotationVisitor NO_ANNOTATION_VISITOR = new AnnotationVisitor(Opcodes.ASM5) {};
|
||||
|
||||
@@ -91,7 +117,6 @@ public abstract class AnnotationCodegen {
|
||||
|
||||
AnnotationDescriptor annotationDescriptor = bindingContext.get(BindingContext.ANNOTATION, annotationEntry);
|
||||
if (annotationDescriptor == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
|
||||
if (isVolatile(annotationDescriptor)) continue;
|
||||
|
||||
String descriptor = genAnnotation(annotationDescriptor);
|
||||
if (descriptor != null) {
|
||||
@@ -149,11 +174,6 @@ public abstract class AnnotationCodegen {
|
||||
return !type.isNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type);
|
||||
}
|
||||
|
||||
private static boolean isVolatile(@NotNull AnnotationDescriptor annotationDescriptor) {
|
||||
ClassifierDescriptor classDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
|
||||
return classDescriptor != null && DescriptorUtils.getFqName(classDescriptor).equals(VOLATILE_FQ_NAME.toUnsafe());
|
||||
}
|
||||
|
||||
public void generateAnnotationDefaultValue(@NotNull CompileTimeConstant value, @NotNull JetType expectedType) {
|
||||
AnnotationVisitor visitor = visitAnnotation(null, false); // Parameters are unimportant
|
||||
genCompileTimeValue(null, value, expectedType, visitor);
|
||||
|
||||
@@ -168,6 +168,12 @@ public class AsmUtil {
|
||||
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
|
||||
int flags = getCommonCallableFlags(functionDescriptor);
|
||||
|
||||
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
|
||||
if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) {
|
||||
flags |= flagAnnotation.getJvmFlag();
|
||||
}
|
||||
}
|
||||
|
||||
if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
|
||||
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
|
||||
if (!(containingDeclaration instanceof ClassDescriptor) ||
|
||||
|
||||
@@ -189,8 +189,10 @@ public class PropertyCodegen {
|
||||
private FieldVisitor generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) {
|
||||
int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
|
||||
|
||||
if (propertyDescriptor.getOriginal().getAnnotations().findAnnotation(AnnotationCodegen.VOLATILE_FQ_NAME) != null) {
|
||||
modifiers |= ACC_VOLATILE;
|
||||
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) {
|
||||
if (flagAnnotation.hasAnnotation(propertyDescriptor.getOriginal())) {
|
||||
modifiers |= flagAnnotation.getJvmFlag();
|
||||
}
|
||||
}
|
||||
|
||||
if (kind == OwnerKind.PACKAGE) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
class C {
|
||||
volatile var vol = 1
|
||||
transient val tra = 1
|
||||
|
||||
strictfp fun str() {}
|
||||
synchronized fun sync() {}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = javaClass<C>()
|
||||
|
||||
if (c.getDeclaredField("vol").getModifiers() and Modifier.VOLATILE == 0) return "Fail: volatile"
|
||||
if (c.getDeclaredField("tra").getModifiers() and Modifier.TRANSIENT == 0) return "Fail: transient"
|
||||
|
||||
if (c.getDeclaredMethod("str").getModifiers() and Modifier.STRICT == 0) return "Fail: strict"
|
||||
if (c.getDeclaredMethod("sync").getModifiers() and Modifier.SYNCHRONIZED == 0) return "Fail: synchronized"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
volatile var vol = 1
|
||||
transient val tra = 1
|
||||
|
||||
strictfp fun str() {}
|
||||
synchronized fun sync() {}
|
||||
|
||||
// 0 kotlin/jvm/volatile
|
||||
// 0 kotlin/jvm/transient
|
||||
// 0 kotlin/jvm/strictfp
|
||||
// 0 kotlin/jvm/synchronized
|
||||
@@ -1,3 +0,0 @@
|
||||
volatile val foo: Int = 1
|
||||
|
||||
// 0 kotlin/volatile
|
||||
@@ -122,9 +122,9 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest("compiler/testData/codegen/bytecodeText/kt5016intOrNull.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noVolatileAnnotation.kt")
|
||||
public void testNoVolatileAnnotation() throws Exception {
|
||||
doTest("compiler/testData/codegen/bytecodeText/noVolatileAnnotation.kt");
|
||||
@TestMetadata("noFlagAnnotations.kt")
|
||||
public void testNoFlagAnnotations() throws Exception {
|
||||
doTest("compiler/testData/codegen/bytecodeText/noFlagAnnotations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noWrapperForMethodReturningPrimitive.kt")
|
||||
|
||||
+5
@@ -48,6 +48,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/defaultParameterValues.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmFlags.kt")
|
||||
public void testJvmFlags() throws Exception {
|
||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/jvmFlags.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinPropertyFromClassObjectAsParameter.kt")
|
||||
public void testKotlinPropertyFromClassObjectAsParameter() throws Exception {
|
||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/kotlinPropertyFromClassObjectAsParameter.kt");
|
||||
|
||||
@@ -24,9 +24,6 @@ public annotation class throws(vararg val exceptionClasses: Class<out Throwable>
|
||||
|
||||
[Intrinsic("kotlin.javaClass.function")] fun <reified T> javaClass() : Class<T> = null as Class<T>
|
||||
|
||||
Retention(RetentionPolicy.SOURCE)
|
||||
public annotation class volatile
|
||||
|
||||
[Intrinsic("kotlin.synchronized")] public fun <R> synchronized(lock: Any, block: () -> R): R = block()
|
||||
|
||||
public fun <T : Annotation> T.annotationType() : Class<out T> =
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 kotlin.jvm
|
||||
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
|
||||
Retention(RetentionPolicy.SOURCE)
|
||||
public annotation class volatile
|
||||
|
||||
Retention(RetentionPolicy.SOURCE)
|
||||
public annotation class transient
|
||||
|
||||
Retention(RetentionPolicy.SOURCE)
|
||||
public annotation class strictfp
|
||||
|
||||
Retention(RetentionPolicy.SOURCE)
|
||||
public annotation class synchronized
|
||||
|
||||
Reference in New Issue
Block a user