From ea0f1b03a9b2533407e22de4043090f43a795c70 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 31 May 2024 18:40:20 -0700 Subject: [PATCH] Do not attempt constant folding of instance fields whose class is initialized at run time --- .../pointsto/heap/ImageHeapConstant.java | 8 +++++++ .../graal/pointsto/heap/ImageHeapScanner.java | 22 ++++++++++++++----- .../meta/SharedConstantFieldProvider.java | 16 +++++++++++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 3f5ca3961b1f..c56be1e33ee4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -163,6 +163,14 @@ public boolean isReachable() { return isReachableHandle.get(constantData) != null; } + public boolean allowConstantFolding() { + /* + * An object whose type is initialized at run time does not have hosted field values. Only + * simulated objects can be used for constant folding. + */ + return constantData.type.isInitialized() || constantData.hostedObject == null; + } + public Object getReachableReason() { return constantData.isReachable; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 7dc95174418b..6daf65f15b11 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -417,11 +417,21 @@ private ImageHeapInstance createImageHeapInstance(JavaConstant constant, Analysi for (ResolvedJavaField javaField : instanceFields) { AnalysisField field = (AnalysisField) javaField; ValueSupplier rawFieldValue; - try { - rawFieldValue = readHostedFieldValue(field, constant); - } catch (InternalError | TypeNotPresentException | LinkageError e) { - /* Ignore missing type errors. */ - continue; + if (!type.isInitialized()) { + /* + * We cannot read the hosted value of an object whose type is initialized at run + * time. If the object is marked as reachable later on, it will be reported as + * an unsupported feature. But we must not fail here earlier with an internal + * error. + */ + rawFieldValue = ValueSupplier.lazyValue(() -> null, () -> false); + } else { + try { + rawFieldValue = readHostedFieldValue(field, constant); + } catch (InternalError | TypeNotPresentException | LinkageError e) { + /* Ignore missing type errors. */ + continue; + } } hostedFieldValues[field.getPosition()] = new AnalysisFuture<>(() -> { ScanReason fieldReason = new FieldScan(field, instance, reason); @@ -621,7 +631,7 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason /* Enhance the unsupported feature message with the object trace and rethrow. */ StringBuilder backtrace = new StringBuilder(); ObjectScanner.buildObjectBacktrace(bb, reason, backtrace); - throw new UnsupportedFeatureException(e.getMessage() + System.lineSeparator() + backtrace); + throw new UnsupportedFeatureException(e.getMessage() + System.lineSeparator() + backtrace, e); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java index 4f097d792e9f..efe327080ae5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java @@ -27,6 +27,7 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.svm.core.meta.MethodPointer; @@ -56,7 +57,7 @@ public SharedConstantFieldProvider(MetaAccessProvider metaAccess, SVMHost hostVM @Override public boolean isFinalField(ResolvedJavaField field, ConstantFieldTool tool) { - return super.isFinalField(field, tool) && allowConstantFolding(field); + return super.isFinalField(field, tool) && allowConstantFolding(field, tool); } @Override @@ -72,12 +73,21 @@ public boolean isStableField(ResolvedJavaField field, ConstantFieldTool tool) } else { stable = super.isStableField(field, tool); } - return stable && allowConstantFolding(field); + return stable && allowConstantFolding(field, tool); } - private boolean allowConstantFolding(ResolvedJavaField field) { + private boolean allowConstantFolding(ResolvedJavaField field, ConstantFieldTool tool) { var aField = asAnalysisField(field); + /* + * During compiler optimizations, it is possible to see field loads with a constant receiver + * of a wrong type that might not even be an ImageHeapConstant. Also, we need to ensure that + * the ImageHeapConstant allows constant folding of its fields. + */ + if (!field.isStatic() && (!(tool.getReceiver() instanceof ImageHeapConstant receiver) || !receiver.allowConstantFolding())) { + return false; + } + /* * This code should run as late as possible, because it has side effects. So we only do it * after we have already checked that the field is `final` or `stable`. It marks the