1
1
/*
2
- * Copyright (c) 2022, 2022 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2022, 2025 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
28
28
import java .util .Set ;
29
29
import java .util .concurrent .ConcurrentHashMap ;
30
30
31
- import org .graalvm .collections .EconomicMap ;
32
- import org .graalvm .collections .MapCursor ;
33
-
34
31
import com .oracle .svm .core .BuildPhaseProvider ;
35
32
import com .oracle .svm .core .feature .AutomaticallyRegisteredFeature ;
36
33
import com .oracle .svm .core .feature .InternalFeature ;
@@ -76,31 +73,46 @@ private Object replaceHostedWithRuntime(Object obj) {
76
73
return obj ;
77
74
}
78
75
76
+ /**
77
+ * This method makes sure that the content of all modified {@link HostedImageHeapMap}s and
78
+ * {@link HostedImageHeapList}s is properly propagated to their runtime counterparts. As both
79
+ * the number of these collections and their individual sizes are theoretically unbounded, we
80
+ * use <i>parallel streams</i> to divide the load across all cores.
81
+ * <p>
82
+ * We split the process into two stages. First, the content of each modified collection is
83
+ * propagated from the hosted to the runtime version. Then, the modified runtime collections are
84
+ * rescanned. The split is done to prevent concurrent modifications of the hosted collections
85
+ * during the execution of this method, as they may be updated indirectly during the heap
86
+ * scanning.
87
+ */
79
88
@ Override
80
89
public void duringAnalysis (DuringAnalysisAccess a ) {
81
90
DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl ) a ;
82
91
if (ImageLayerBuildingSupport .buildingExtensionLayer ()) {
83
92
allMaps .addAll (LayeredHostedImageHeapMapCollector .singleton ().getPreviousLayerReachableMaps ());
84
93
}
85
- for ( var hostedImageHeapMap : allMaps ) {
86
- if ( needsUpdate (hostedImageHeapMap )) {
87
- update (hostedImageHeapMap );
88
- access . rescanObject ( hostedImageHeapMap .getCurrentLayerMap () );
89
- access . requireAnalysisIteration ( );
94
+ Set < Object > objectsToRescan = ConcurrentHashMap . newKeySet ();
95
+ allMaps . parallelStream (). forEach (hostedImageHeapMap -> {
96
+ if (hostedImageHeapMap . needsUpdate ()) {
97
+ hostedImageHeapMap .update ( );
98
+ objectsToRescan . add ( hostedImageHeapMap . getCurrentLayerMap () );
90
99
}
91
- }
92
- for ( var hostedImageHeapList : allLists ) {
100
+ });
101
+ allLists . parallelStream (). forEach ( hostedImageHeapList -> {
93
102
if (hostedImageHeapList .needsUpdate ()) {
94
103
hostedImageHeapList .update ();
95
- access .rescanObject (hostedImageHeapList .runtimeList );
96
- access .requireAnalysisIteration ();
104
+ objectsToRescan .add (hostedImageHeapList .runtimeList );
97
105
}
106
+ });
107
+ if (!objectsToRescan .isEmpty ()) {
108
+ objectsToRescan .parallelStream ().forEach (access ::rescanObject );
109
+ access .requireAnalysisIteration ();
98
110
}
99
111
}
100
112
101
113
public boolean needsUpdate () {
102
114
for (var hostedImageHeapMap : allMaps ) {
103
- if (needsUpdate (hostedImageHeapMap )) {
115
+ if (hostedImageHeapMap . needsUpdate ()) {
104
116
return true ;
105
117
}
106
118
}
@@ -115,7 +127,7 @@ public boolean needsUpdate() {
115
127
@ Override
116
128
public void afterImageWrite (AfterImageWriteAccess access ) {
117
129
for (var hostedImageHeapMap : allMaps ) {
118
- if (needsUpdate (hostedImageHeapMap )) {
130
+ if (hostedImageHeapMap . needsUpdate ()) {
119
131
throw VMError .shouldNotReachHere ("ImageHeapMap modified after static analysis:%n%s%n%s" ,
120
132
hostedImageHeapMap , hostedImageHeapMap .getCurrentLayerMap ());
121
133
}
@@ -128,25 +140,4 @@ public void afterImageWrite(AfterImageWriteAccess access) {
128
140
}
129
141
}
130
142
}
131
-
132
- private static boolean needsUpdate (HostedImageHeapMap <?, ?> hostedMap ) {
133
- EconomicMap <Object , Object > runtimeMap = hostedMap .getCurrentLayerMap ();
134
- if (hostedMap .size () != runtimeMap .size ()) {
135
- return true ;
136
- }
137
- MapCursor <?, ?> hostedEntry = hostedMap .getEntries ();
138
- while (hostedEntry .advance ()) {
139
- Object hostedValue = hostedEntry .getValue ();
140
- Object runtimeValue = runtimeMap .get (hostedEntry .getKey ());
141
- if (hostedValue != runtimeValue ) {
142
- return true ;
143
- }
144
- }
145
- return false ;
146
- }
147
-
148
- private static void update (HostedImageHeapMap <?, ?> hostedMap ) {
149
- hostedMap .getCurrentLayerMap ().clear ();
150
- hostedMap .getCurrentLayerMap ().putAll (hostedMap );
151
- }
152
143
}
0 commit comments