diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java index bdddd861162..4259c6f290f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java @@ -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 FIELD_FLAGS = Arrays.asList( + new JvmFlagAnnotation("kotlin.jvm.volatile", Opcodes.ACC_VOLATILE), + new JvmFlagAnnotation("kotlin.jvm.transient", Opcodes.ACC_TRANSIENT) + ); + + public static final List 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); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index e9ed5da8688..3e2b64e249f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -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) || diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 18f022d423d..5e447daaf38 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -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) { diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/jvmFlags.kt b/compiler/testData/codegen/boxWithStdlib/annotations/jvmFlags.kt new file mode 100644 index 00000000000..eed1985cd64 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/jvmFlags.kt @@ -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() + + 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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/noFlagAnnotations.kt b/compiler/testData/codegen/bytecodeText/noFlagAnnotations.kt new file mode 100644 index 00000000000..ed21c9131f9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/noFlagAnnotations.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/noVolatileAnnotation.kt b/compiler/testData/codegen/bytecodeText/noVolatileAnnotation.kt deleted file mode 100644 index 11dc5d3f182..00000000000 --- a/compiler/testData/codegen/bytecodeText/noVolatileAnnotation.kt +++ /dev/null @@ -1,3 +0,0 @@ -volatile val foo: Int = 1 - -// 0 kotlin/volatile diff --git a/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java index 5bda0c1b766..269eef9a9de 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java @@ -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") diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 3e17574daba..840c767b4fd 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -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"); diff --git a/libraries/stdlib/src/kotlin/JLangJVM.kt b/libraries/stdlib/src/kotlin/JLangJVM.kt index 4f60e0edb2e..64a12e62433 100644 --- a/libraries/stdlib/src/kotlin/JLangJVM.kt +++ b/libraries/stdlib/src/kotlin/JLangJVM.kt @@ -24,9 +24,6 @@ public annotation class throws(vararg val exceptionClasses: Class [Intrinsic("kotlin.javaClass.function")] fun javaClass() : Class = null as Class -Retention(RetentionPolicy.SOURCE) -public annotation class volatile - [Intrinsic("kotlin.synchronized")] public fun synchronized(lock: Any, block: () -> R): R = block() public fun T.annotationType() : Class = diff --git a/libraries/stdlib/src/kotlin/jvm/JvmFlagAnnotations.kt b/libraries/stdlib/src/kotlin/jvm/JvmFlagAnnotations.kt new file mode 100644 index 00000000000..18ff6a72b40 --- /dev/null +++ b/libraries/stdlib/src/kotlin/jvm/JvmFlagAnnotations.kt @@ -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 +