Skip to content

Commit b2203ac

Browse files
author
Christian Wimmer
committed
Do not mark AnalysisType reachable when creating AnalysisField
1 parent 4343add commit b2203ac

File tree

45 files changed

+1147
-648
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1147
-648
lines changed

substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@
2929
import java.util.Comparator;
3030
import java.util.concurrent.ConcurrentHashMap;
3131

32-
import jdk.graal.compiler.java.GraphBuilderPhase;
33-
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
34-
import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext;
35-
import jdk.graal.compiler.options.OptionValues;
36-
import jdk.graal.compiler.phases.OptimisticOptimizations;
37-
32+
import com.oracle.graal.pointsto.BigBang;
3833
import com.oracle.graal.pointsto.api.HostVM;
3934
import com.oracle.graal.pointsto.meta.AnalysisType;
4035
import com.oracle.graal.pointsto.meta.HostedProviders;
4136
import com.oracle.graal.pointsto.standalone.plugins.StandaloneGraphBuilderPhase;
4237
import com.oracle.graal.pointsto.util.AnalysisError;
4338

39+
import jdk.graal.compiler.java.GraphBuilderPhase;
40+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
41+
import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext;
42+
import jdk.graal.compiler.options.OptionValues;
43+
import jdk.graal.compiler.phases.OptimisticOptimizations;
4444
import jdk.vm.ci.meta.ResolvedJavaType;
4545

4646
public class StandaloneHost extends HostVM {
@@ -72,7 +72,7 @@ public boolean isInitialized(AnalysisType type) {
7272
}
7373

7474
@Override
75-
public void onTypeReachable(AnalysisType type) {
75+
public void onTypeReachable(BigBang bb, AnalysisType type) {
7676
if (!type.isReachable()) {
7777
AnalysisError.shouldNotReachHere("Registering and initializing a type that was not yet marked as reachable: " + type);
7878
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,9 @@
4141
import com.oracle.graal.pointsto.BigBang;
4242
import com.oracle.graal.pointsto.PointsToAnalysis;
4343
import com.oracle.graal.pointsto.flow.InvokeTypeFlow;
44-
import com.oracle.graal.pointsto.meta.AnalysisField;
4544
import com.oracle.graal.pointsto.meta.AnalysisMethod;
4645
import com.oracle.graal.pointsto.meta.AnalysisType;
4746
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
48-
import com.oracle.graal.pointsto.meta.FieldValueComputer;
4947
import com.oracle.graal.pointsto.meta.HostedProviders;
5048
import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder;
5149
import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy;
@@ -155,7 +153,7 @@ public void checkType(ResolvedJavaType type, AnalysisUniverse universe) {
155153
*
156154
* @param newValue the type to initialize
157155
*/
158-
public abstract void onTypeReachable(AnalysisType newValue);
156+
public abstract void onTypeReachable(BigBang bb, AnalysisType newValue);
159157

160158
/**
161159
* Check if an {@link AnalysisType} is initialized.
@@ -420,8 +418,4 @@ public boolean allowConstantFolding(AnalysisMethod method) {
420418
*/
421419
return method.isOriginalMethod();
422420
}
423-
424-
public FieldValueComputer createFieldValueComputer(@SuppressWarnings("unused") AnalysisField field) {
425-
return null;
426-
}
427421
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ private void updateInstanceField(AnalysisField field, ImageHeapInstance imageHea
545545
}
546546

547547
public boolean isValueAvailable(AnalysisField field) {
548-
return field.isValueAvailable();
548+
return true;
549549
}
550550

551551
protected String formatReason(String message, ScanReason reason) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/LazyValueSupplier.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.oracle.graal.pointsto.heap.value;
2626

27+
import java.util.Objects;
2728
import java.util.function.BooleanSupplier;
2829
import java.util.function.Supplier;
2930

@@ -47,6 +48,6 @@ public boolean isAvailable() {
4748
@Override
4849
public V get() {
4950
AnalysisError.guarantee(isAvailable(), "Value is not yet available.");
50-
return valueSupplier.get();
51+
return Objects.requireNonNull(valueSupplier.get());
5152
}
5253
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/ValueSupplier.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.oracle.graal.pointsto.heap.value;
2626

27+
import java.util.Objects;
2728
import java.util.function.BooleanSupplier;
2829
import java.util.function.Supplier;
2930

@@ -42,7 +43,7 @@
4243
public interface ValueSupplier<V> {
4344

4445
static <V> ValueSupplier<V> eagerValue(V value) {
45-
return new EagerValueSupplier<>(value);
46+
return new EagerValueSupplier<>(Objects.requireNonNull(value));
4647
}
4748

4849
static <V> ValueSupplier<V> lazyValue(Supplier<V> valueSupplier, BooleanSupplier isAvailable) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalClassProvider.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,21 @@
2828

2929
import com.oracle.graal.pointsto.util.GraalAccess;
3030

31+
import jdk.vm.ci.meta.JavaType;
3132
import jdk.vm.ci.meta.ResolvedJavaType;
3233

3334
public interface OriginalClassProvider {
3435

35-
static Class<?> getJavaClass(ResolvedJavaType javaType) {
36+
static Class<?> getJavaClass(JavaType javaType) {
3637
Class<?> result;
3738
if (javaType instanceof OriginalClassProvider) {
3839
result = ((OriginalClassProvider) javaType).getJavaClass();
3940
} else {
40-
result = GraalAccess.getOriginalSnippetReflection().originalClass(javaType);
41+
/*
42+
* The static analysis and the image generator never use unresolved types. The JavaType
43+
* in the method signature is just to avoid casts in the callers.
44+
*/
45+
result = GraalAccess.getOriginalSnippetReflection().originalClass((ResolvedJavaType) javaType);
4146
}
4247

4348
/*

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,28 @@
4141
*/
4242
public interface OriginalFieldProvider {
4343

44+
static ResolvedJavaField getOriginalField(ResolvedJavaField field) {
45+
ResolvedJavaField cur = field;
46+
while (cur instanceof OriginalFieldProvider originalFieldProvider) {
47+
cur = originalFieldProvider.unwrapTowardsOriginalField();
48+
}
49+
return cur;
50+
}
51+
4452
static Field getJavaField(ResolvedJavaField field) {
45-
if (field instanceof OriginalFieldProvider) {
46-
return ((OriginalFieldProvider) field).getJavaField();
47-
} else {
53+
ResolvedJavaField originalField = getOriginalField(field);
54+
if (originalField != null) {
4855
try {
49-
return GraalAccess.getOriginalSnippetReflection().originalField(field);
56+
return GraalAccess.getOriginalSnippetReflection().originalField(originalField);
5057
} catch (LinkageError ignored) {
5158
/*
5259
* Ignore any linking problems and incompatible class change errors. Looking up a
5360
* reflective representation of a JVMCI field is always a best effort operation.
5461
*/
55-
return null;
5662
}
5763
}
64+
return null;
5865
}
5966

60-
Field getJavaField();
67+
ResolvedJavaField unwrapTowardsOriginalField();
6168
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@
2424
*/
2525
package com.oracle.graal.pointsto.meta;
2626

27-
import java.lang.reflect.Field;
2827
import java.lang.reflect.Modifier;
2928
import java.util.ArrayList;
29+
import java.util.List;
3030
import java.util.concurrent.ConcurrentHashMap;
3131
import java.util.concurrent.ConcurrentMap;
3232
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
3333
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
3434

35-
import jdk.graal.compiler.debug.GraalError;
36-
3735
import com.oracle.graal.pointsto.api.DefaultUnsafePartition;
3836
import com.oracle.graal.pointsto.api.HostVM;
3937
import com.oracle.graal.pointsto.api.PointstoOptions;
@@ -42,10 +40,12 @@
4240
import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider;
4341
import com.oracle.graal.pointsto.infrastructure.WrappedJavaField;
4442
import com.oracle.graal.pointsto.typestate.TypeState;
43+
import com.oracle.graal.pointsto.util.AnalysisFuture;
4544
import com.oracle.graal.pointsto.util.AtomicUtils;
4645
import com.oracle.graal.pointsto.util.ConcurrentLightHashSet;
4746
import com.oracle.svm.util.UnsafePartitionKind;
4847

48+
import jdk.graal.compiler.debug.GraalError;
4949
import jdk.vm.ci.code.BytecodePosition;
5050
import jdk.vm.ci.meta.JavaConstant;
5151
import jdk.vm.ci.meta.JavaKind;
@@ -123,9 +123,10 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa
123123

124124
/**
125125
* Marks a field whose value is computed during image building, in general derived from other
126-
* values, and it cannot be constant-folded or otherwise optimized.
126+
* values. The actual meaning of the field value is out of scope of the static analysis, but the
127+
* value is stored here to allow fast access.
127128
*/
128-
protected final FieldValueComputer fieldValueComputer;
129+
protected Object fieldValueInterceptor;
129130

130131
@SuppressWarnings("this-escape")
131132
public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) {
@@ -152,8 +153,6 @@ public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField)
152153
this.instanceFieldFlow = new ContextInsensitiveFieldTypeFlow(this, getType());
153154
this.initialInstanceFieldFlow = new FieldTypeFlow(this, getType());
154155
}
155-
156-
fieldValueComputer = universe.hostVM().createFieldValueComputer(this);
157156
}
158157

159158
@Override
@@ -260,6 +259,8 @@ public void cleanupAfterAnalysis() {
260259
}
261260

262261
public boolean registerAsAccessed(Object reason) {
262+
getDeclaringClass().registerAsReachable(this);
263+
263264
assert isValidReason(reason) : "Registering a field as accessed needs to provide a valid reason.";
264265
boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isAccessedUpdater);
265266
notifyUpdateAccessInfo();
@@ -275,6 +276,8 @@ public boolean registerAsAccessed(Object reason) {
275276
* @param reason the reason why this field is read, non-null
276277
*/
277278
public boolean registerAsRead(Object reason) {
279+
getDeclaringClass().registerAsReachable(this);
280+
278281
assert isValidReason(reason) : "Registering a field as read needs to provide a valid reason.";
279282
boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isReadUpdater);
280283
notifyUpdateAccessInfo();
@@ -295,6 +298,8 @@ public boolean registerAsRead(Object reason) {
295298
* @param reason the reason why this field is written, non-null
296299
*/
297300
public boolean registerAsWritten(Object reason) {
301+
getDeclaringClass().registerAsReachable(this);
302+
298303
assert isValidReason(reason) : "Registering a field as written needs to provide a valid reason.";
299304
boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isWrittenUpdater);
300305
notifyUpdateAccessInfo();
@@ -311,6 +316,8 @@ public boolean registerAsWritten(Object reason) {
311316
}
312317

313318
public void registerAsFolded(Object reason) {
319+
getDeclaringClass().registerAsReachable(this);
320+
314321
assert isValidReason(reason) : "Registering a field as folded needs to provide a valid reason.";
315322
if (AtomicUtils.atomicSet(this, reason, isFoldedUpdater)) {
316323
assert getDeclaringClass().isReachable() : this;
@@ -442,23 +449,12 @@ public void onReachable() {
442449
notifyReachabilityCallbacks(declaringClass.getUniverse(), new ArrayList<>());
443450
}
444451

445-
public boolean isValueAvailable() {
446-
if (fieldValueComputer != null) {
447-
return fieldValueComputer.isAvailable();
448-
}
449-
return true;
450-
}
451-
452-
public boolean isComputedValue() {
453-
return fieldValueComputer != null;
454-
}
455-
456-
public Class<?>[] computedValueTypes() {
457-
return fieldValueComputer.types();
452+
public Object getFieldValueInterceptor() {
453+
return fieldValueInterceptor;
458454
}
459455

460-
public boolean computedValueCanBeNull() {
461-
return fieldValueComputer.canBeNull();
456+
public void setFieldValueInterceptor(Object fieldValueInterceptor) {
457+
this.fieldValueInterceptor = fieldValueInterceptor;
462458
}
463459

464460
public void setCanBeNull(boolean canBeNull) {
@@ -531,15 +527,34 @@ public String toString() {
531527
}
532528

533529
@Override
534-
public Field getJavaField() {
535-
return OriginalFieldProvider.getJavaField(wrapped);
530+
public ResolvedJavaField unwrapTowardsOriginalField() {
531+
return wrapped;
536532
}
537533

538534
@Override
539535
public JavaConstant getConstantValue() {
540536
return getUniverse().lookup(getWrapped().getConstantValue());
541537
}
542538

539+
/**
540+
* Ensure that all reachability handler that were present at the time the declaring type was
541+
* marked as reachable are executed before accessing field values. This allows field value
542+
* transformer to be installed reliably in reachability handler.
543+
*/
544+
public void beforeFieldValueAccess() {
545+
declaringClass.registerAsReachable(this);
546+
declaringClass.ensureOnTypeReachableTaskDone();
547+
548+
List<AnalysisFuture<Void>> notifications = declaringClass.scheduledTypeReachableNotifications;
549+
if (notifications != null) {
550+
for (var notification : notifications) {
551+
notification.ensureDone();
552+
}
553+
/* Now we know all the handlers have been executed, no checks are necessary anymore. */
554+
declaringClass.scheduledTypeReachableNotifications = null;
555+
}
556+
}
557+
543558
public void addAnalysisFieldObserver(AnalysisFieldObserver observer) {
544559
ConcurrentLightHashSet.addElement(this, OBSERVERS_UPDATER, observer);
545560
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,13 +681,18 @@ private static void forAllSuperTypes(AnalysisType elementType, int arrayDimensio
681681
if (elementType == null) {
682682
return;
683683
}
684-
if (processType) {
685-
superTypeConsumer.accept(elementType.getArrayClass(arrayDimension));
686-
}
687684
for (AnalysisType interf : elementType.getInterfaces()) {
688685
forAllSuperTypes(interf, arrayDimension, true, superTypeConsumer);
689686
}
690687
forAllSuperTypes(elementType.getSuperclass(), arrayDimension, true, superTypeConsumer);
688+
/*
689+
* Process the type itself only after visiting all supertypes. This ensures that, e.g., a
690+
* type is never seen as reachable by another thread before all of its supertypes are
691+
* already marked as reachable too.
692+
*/
693+
if (processType) {
694+
superTypeConsumer.accept(elementType.getArrayClass(arrayDimension));
695+
}
691696
}
692697

693698
protected synchronized void addAssignableType(BigBang bb, TypeState typeState) {

0 commit comments

Comments
 (0)