Support transient, strictfp and synchronized flags

#KT-4377 Fixed
This commit is contained in:
Andrey Breslav
2014-06-17 20:17:10 +04:00
parent f2bc26888c
commit 512e4cb75e
10 changed files with 111 additions and 20 deletions
@@ -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")
@@ -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");
-3
View File
@@ -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