cleanup
[idea/community.git] / platform / util / src / com / intellij / util / concurrency / AtomicFieldUpdater.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2
3 package com.intellij.util.concurrency;
4
5 import com.intellij.util.ReflectionUtil;
6 import org.jetbrains.annotations.NotNull;
7 import sun.misc.Unsafe;
8
9 import java.lang.reflect.Field;
10 import java.lang.reflect.Modifier;
11
12 /**
13  * Utility class similar to {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater} except:
14  * - removed access check in getAndSet() hot path for performance
15  * - new methods "forFieldXXX" added that search by field type instead of field name, which is useful in scrambled classes
16  */
17 public final class AtomicFieldUpdater<ContainingClass, FieldType> {
18   private static final Unsafe unsafe;
19   static {
20     unsafe = ReflectionUtil.getStaticFieldValue(Unsafe.class, Unsafe.class, "theUnsafe");
21     if (unsafe == null) {
22       throw new RuntimeException("Could not find 'theUnsafe' field in the " + Unsafe.class);
23     }
24   }
25
26   public static @NotNull Unsafe getUnsafe() {
27     return unsafe;
28   }
29
30   private final long offset;
31
32   public static @NotNull <T, V> AtomicFieldUpdater<T, V> forFieldOfType(@NotNull Class<T> ownerClass, @NotNull Class<V> fieldType) {
33     return new AtomicFieldUpdater<>(ownerClass, fieldType);
34   }
35
36   public static @NotNull <T> AtomicFieldUpdater<T, Long> forLongFieldIn(@NotNull Class<T> ownerClass) {
37     return new AtomicFieldUpdater<>(ownerClass, long.class);
38   }
39
40   public static @NotNull <T> AtomicFieldUpdater<T, Integer> forIntFieldIn(@NotNull Class<T> ownerClass) {
41     return new AtomicFieldUpdater<>(ownerClass, int.class);
42   }
43
44   public static @NotNull <O,E> AtomicFieldUpdater<O, E> forField(@NotNull Field field) {
45     return new AtomicFieldUpdater<>(field);
46   }
47
48   private AtomicFieldUpdater(@NotNull Class<ContainingClass> ownerClass, @NotNull Class<FieldType> fieldType) {
49     this(ReflectionUtil.getTheOnlyVolatileInstanceFieldOfClass(ownerClass, fieldType));
50   }
51
52   private AtomicFieldUpdater(@NotNull Field field) {
53     field.setAccessible(true);
54     if (!Modifier.isVolatile(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) throw new IllegalArgumentException(field + " must be volatile instance");
55     offset = unsafe.objectFieldOffset(field);
56   }
57
58   public boolean compareAndSet(@NotNull ContainingClass owner, FieldType expected, FieldType newValue) {
59     return unsafe.compareAndSwapObject(owner, offset, expected, newValue);
60   }
61
62   public boolean compareAndSetLong(@NotNull ContainingClass owner, long expected, long newValue) {
63     return unsafe.compareAndSwapLong(owner, offset, expected, newValue);
64   }
65
66   public boolean compareAndSetInt(@NotNull ContainingClass owner, int expected, int newValue) {
67     return unsafe.compareAndSwapInt(owner, offset, expected, newValue);
68   }
69
70   public void set(@NotNull ContainingClass owner, FieldType newValue) {
71     unsafe.putObjectVolatile(owner, offset, newValue);
72   }
73
74   public FieldType get(@NotNull ContainingClass owner) {
75     //noinspection unchecked
76     return (FieldType)unsafe.getObjectVolatile(owner, offset);
77   }
78 }