Skip to content

Commit f3e37ce

Browse files
committed
Make reachability handlers thread safe.
1 parent c74a8d5 commit f3e37ce

File tree

5 files changed

+23
-14
lines changed

5 files changed

+23
-14
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JNIRegistrationUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.lang.reflect.Field;
2929
import java.lang.reflect.Method;
3030
import java.util.Collections;
31-
import java.util.IdentityHashMap;
3231
import java.util.Optional;
3332
import java.util.Set;
3433
import java.util.function.Consumer;
@@ -41,6 +40,7 @@
4140
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
4241

4342
import com.oracle.svm.core.jni.JNIRuntimeAccess;
43+
import com.oracle.svm.core.util.ConcurrentIdentityHashMap;
4444
import com.oracle.svm.core.util.VMError;
4545
import com.oracle.svm.util.ReflectionUtil;
4646

@@ -111,7 +111,7 @@ protected static void registerForThrowNew(FeatureAccess access, String... except
111111
}
112112
}
113113

114-
private static Set<Consumer<DuringAnalysisAccess>> runOnceCallbacks = Collections.newSetFromMap(new IdentityHashMap<>());
114+
private static final Set<Consumer<DuringAnalysisAccess>> runOnceCallbacks = Collections.newSetFromMap(new ConcurrentIdentityHashMap<>());
115115

116116
/** Intended to be used from within a callback to ensure that it is run only once. */
117117
protected static boolean isRunOnce(Consumer<DuringAnalysisAccess> callback) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NativeLibrarySupport.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.io.IOException;
2929
import java.util.ArrayDeque;
3030
import java.util.ArrayList;
31+
import java.util.Collections;
3132
import java.util.Deque;
3233
import java.util.List;
3334
import java.util.concurrent.locks.ReentrantLock;
@@ -70,7 +71,7 @@ public static NativeLibrarySupport singleton() {
7071

7172
private final ReentrantLock lock = new ReentrantLock();
7273

73-
private final List<NativeLibrary> knownLibraries = new ArrayList<>();
74+
private final List<NativeLibrary> knownLibraries = Collections.synchronizedList(new ArrayList<>());
7475

7576
private final Deque<NativeLibrary> currentLoadContext = new ArrayDeque<>();
7677

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public static class Options {
173173
private Map<String, Set<Service>> availableServices;
174174

175175
/** All providers deemed to be used by this feature. */
176-
private final Set<Provider> usedProviders = new HashSet<>();
176+
private final Set<Provider> usedProviders = ConcurrentHashMap.newKeySet();
177177

178178
/** Providers marked as used by the user. */
179179
private final Set<String> manuallyMarkedUsedProviderClassNames = new HashSet<>();
@@ -684,8 +684,7 @@ private static void registerSpiClass(Method getSpiClassMethod, String serviceTyp
684684
}
685685

686686
private void registerProvider(Provider provider) {
687-
if (!usedProviders.contains(provider)) {
688-
usedProviders.add(provider);
687+
if (usedProviders.add(provider)) {
689688
registerForReflection(provider.getClass());
690689
/* Trigger initialization of lazy field java.security.Provider.entrySet. */
691690
provider.entrySet();

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,12 @@ public DependencyGraph() {
165165
public void add(String library, Collection<String> dependencies) {
166166
UserError.guarantee(library != null, "The library name must be not null and not empty");
167167

168-
Dependency libraryDependency = putWhenAbsent(library, new Dependency(library, new HashSet<>()));
168+
Dependency libraryDependency = putWhenAbsent(library, new Dependency(library, ConcurrentHashMap.newKeySet()));
169169
Set<Dependency> collectedDependencies = libraryDependency.getDependencies();
170170

171171
for (String dependency : dependencies) {
172172
collectedDependencies.add(putWhenAbsent(
173-
dependency, new Dependency(dependency, new HashSet<>())));
173+
dependency, new Dependency(dependency, ConcurrentHashMap.newKeySet())));
174174
}
175175
}
176176

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.ServiceLoader;
4444
import java.util.Set;
4545
import java.util.concurrent.ConcurrentHashMap;
46+
import java.util.concurrent.atomic.AtomicInteger;
4647
import java.util.function.BiConsumer;
4748
import java.util.function.BooleanSupplier;
4849

@@ -479,17 +480,25 @@ private void registerUnsafeAccess(DuringAnalysisAccess access,
479480
*/
480481
static class PossibleReplaceCandidatesSubtypeHandler implements BiConsumer<DuringAnalysisAccess, Class<?>> {
481482

482-
final List<Field> fields = new ArrayList<>();
483+
/**
484+
* The fields are added serially, from the duringAnalysis phase which is run when the
485+
* analysis reaches a local fix point, so no need for synchronization.
486+
*/
487+
List<Field> fields = new ArrayList<>();
483488
final Class<?> fieldType;
484-
int candidateCount;
489+
/**
490+
* The candidates are counted from a reachability handler, which is run in parallel with the
491+
* analysis.
492+
*/
493+
final AtomicInteger candidateCount = new AtomicInteger(0);
485494

486495
PossibleReplaceCandidatesSubtypeHandler(Class<?> fieldType) {
487496
this.fieldType = fieldType;
488497
}
489498

490499
void addField(DuringAnalysisAccess access, Field field) {
491500
assert field.getType() == fieldType;
492-
if (candidateCount > 1) {
501+
if (candidateCount.get() > 1) {
493502
/*
494503
* Limit already reached no need to remember fields anymore we can directly register
495504
* them as unsafe accessed.
@@ -517,13 +526,13 @@ public void accept(DuringAnalysisAccess t, Class<?> u) {
517526
if (Modifier.isAbstract(u.getModifiers())) {
518527
return;
519528
}
520-
candidateCount++;
521529

522-
if (candidateCount > 1) {
530+
/* Limit reached, register the fields and clear the list. */
531+
if (candidateCount.incrementAndGet() == 2) {
523532
for (Field field : fields) {
524533
t.registerAsUnsafeAccessed(field);
525534
}
526-
fields.clear();
535+
fields = null;
527536
}
528537
}
529538

0 commit comments

Comments
 (0)