|
46 | 46 | import java.util.concurrent.CopyOnWriteArrayList; |
47 | 47 | import java.util.function.BiPredicate; |
48 | 48 |
|
49 | | -import com.oracle.svm.core.jdk.InternalVMMethod; |
50 | | -import com.oracle.svm.core.jdk.LambdaFormHiddenMethod; |
51 | 49 | import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; |
52 | 50 | import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; |
53 | 51 | import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; |
|
105 | 103 | import com.oracle.svm.core.hub.HubType; |
106 | 104 | import com.oracle.svm.core.hub.ReferenceType; |
107 | 105 | import com.oracle.svm.core.jdk.ClassLoaderSupport; |
| 106 | +import com.oracle.svm.core.jdk.InternalVMMethod; |
| 107 | +import com.oracle.svm.core.jdk.LambdaFormHiddenMethod; |
108 | 108 | import com.oracle.svm.core.jdk.RecordSupport; |
109 | 109 | import com.oracle.svm.core.jdk.SealedClassSupport; |
110 | 110 | import com.oracle.svm.core.option.HostedOptionKey; |
|
116 | 116 | import com.oracle.svm.hosted.code.InliningUtilities; |
117 | 117 | import com.oracle.svm.hosted.code.UninterruptibleAnnotationChecker; |
118 | 118 | import com.oracle.svm.hosted.heap.PodSupport; |
| 119 | +import com.oracle.svm.hosted.meta.HostedField; |
119 | 120 | import com.oracle.svm.hosted.meta.HostedType; |
120 | 121 | import com.oracle.svm.hosted.meta.HostedUniverse; |
121 | 122 | import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase; |
@@ -157,6 +158,8 @@ public class SVMHost extends HostVM { |
157 | 158 | private final ConcurrentMap<AnalysisMethod, Set<AnalysisType>> initializedClasses = new ConcurrentHashMap<>(); |
158 | 159 | private final ConcurrentMap<AnalysisMethod, Boolean> analysisTrivialMethods = new ConcurrentHashMap<>(); |
159 | 160 |
|
| 161 | + private final Set<AnalysisField> finalFieldsStoredOutsideOfConstructor = ConcurrentHashMap.newKeySet(); |
| 162 | + |
160 | 163 | public SVMHost(OptionValues options, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, |
161 | 164 | UnsafeAutomaticSubstitutionProcessor automaticSubstitutions, Platform platform, SnippetReflectionProvider originalSnippetReflection) { |
162 | 165 | super(options, classLoader); |
@@ -219,7 +222,7 @@ public void checkForbidden(AnalysisType type, AnalysisType.UsageKind kind) { |
219 | 222 |
|
220 | 223 | @Override |
221 | 224 | public Instance createGraphBuilderPhase(HostedProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { |
222 | | - return new AnalysisGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, providers.getWordTypes()); |
| 225 | + return new AnalysisGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, providers.getWordTypes(), this); |
223 | 226 | } |
224 | 227 |
|
225 | 228 | @Override |
@@ -774,4 +777,29 @@ public Comparator<? super ResolvedJavaType> getTypeComparator() { |
774 | 777 | return HostedUniverse.TYPE_COMPARATOR.compare((HostedType) o1, (HostedType) o2); |
775 | 778 | }; |
776 | 779 | } |
| 780 | + |
| 781 | + /** |
| 782 | + * According to the Java VM specification, final instance fields are only allowed to be written |
| 783 | + * in a constructor. But some compilers violate the spec, notably the Scala compiler. This means |
| 784 | + * final fields of image heap objects can be modified at image run time, and constant folding |
| 785 | + * such fields at image build time would fold in the wrong value. As a workaround, we record |
| 786 | + * which final instance fields are written outside of a constructor, and disable constant |
| 787 | + * folding for those fields. |
| 788 | + * |
| 789 | + * Note that there can be races: A constant folding can happen during bytecode parsing before |
| 790 | + * the store was recorded. Currently, we do not encounter that problem because constant folding |
| 791 | + * only happens after static analysis. But there would not be a good solution other than |
| 792 | + * aborting the image build, because a constant folding cannot be reversed. |
| 793 | + */ |
| 794 | + public void recordFieldStore(ResolvedJavaField field, ResolvedJavaMethod method) { |
| 795 | + if (!field.isStatic() && field.isFinal() && (!method.isConstructor() || !field.getDeclaringClass().equals(method.getDeclaringClass()))) { |
| 796 | + AnalysisField aField = field instanceof HostedField ? ((HostedField) field).getWrapped() : (AnalysisField) field; |
| 797 | + finalFieldsStoredOutsideOfConstructor.add(aField); |
| 798 | + } |
| 799 | + } |
| 800 | + |
| 801 | + public boolean preventConstantFolding(ResolvedJavaField field) { |
| 802 | + AnalysisField aField = field instanceof HostedField ? ((HostedField) field).getWrapped() : (AnalysisField) field; |
| 803 | + return finalFieldsStoredOutsideOfConstructor.contains(aField); |
| 804 | + } |
777 | 805 | } |
0 commit comments