3232import org .graalvm .compiler .debug .DebugContext ;
3333import org .graalvm .compiler .debug .GraalError ;
3434import org .graalvm .compiler .nodes .CallTargetNode .InvokeKind ;
35+ import org .graalvm .compiler .nodes .FixedNode ;
36+ import org .graalvm .compiler .nodes .FixedWithNextNode ;
37+ import org .graalvm .compiler .nodes .FrameState ;
38+ import org .graalvm .compiler .nodes .InvokeWithExceptionNode ;
3539import org .graalvm .compiler .nodes .StructuredGraph ;
40+ import org .graalvm .compiler .nodes .UnreachableBeginNode ;
41+ import org .graalvm .compiler .nodes .UnwindNode ;
3642import org .graalvm .compiler .nodes .ValueNode ;
3743import org .graalvm .compiler .nodes .calc .AddNode ;
38- import org .graalvm .compiler .nodes .java .AbstractNewObjectNode ;
3944import org .graalvm .compiler .nodes .java .ArrayLengthNode ;
45+ import org .graalvm .compiler .nodes .java .ExceptionObjectNode ;
4046
4147import com .oracle .graal .pointsto .infrastructure .SubstitutionProcessor ;
42- import com .oracle .graal .pointsto .infrastructure .UniverseMetaAccess ;
4348import com .oracle .graal .pointsto .meta .HostedProviders ;
49+ import com .oracle .svm .core .annotate .DeoptTest ;
50+ import com .oracle .svm .core .graal .nodes .DeoptEntryBeginNode ;
51+ import com .oracle .svm .core .graal .nodes .DeoptEntryNode ;
52+ import com .oracle .svm .core .graal .nodes .LoweredDeadEndNode ;
4453import com .oracle .svm .core .graal .nodes .SubstrateNewHybridInstanceNode ;
54+ import com .oracle .svm .core .graal .nodes .TestDeoptimizeNode ;
4555import com .oracle .svm .core .heap .Pod ;
4656import com .oracle .svm .core .heap .Pod .RuntimeSupport .PodFactory ;
57+ import com .oracle .svm .core .meta .SharedMethod ;
4758import com .oracle .svm .hosted .annotation .CustomSubstitutionMethod ;
59+ import com .oracle .svm .hosted .nodes .DeoptProxyNode ;
4860import com .oracle .svm .hosted .phases .HostedGraphKit ;
4961
62+ import jdk .vm .ci .meta .JavaKind ;
5063import jdk .vm .ci .meta .ResolvedJavaField ;
5164import jdk .vm .ci .meta .ResolvedJavaMethod ;
5265import jdk .vm .ci .meta .ResolvedJavaType ;
@@ -77,32 +90,25 @@ final class PodFactorySubstitutionMethod extends CustomSubstitutionMethod {
7790 super (original );
7891 }
7992
93+ @ Override
94+ public boolean allowRuntimeCompilation () {
95+ return true ;
96+ }
97+
8098 @ Override
8199 public int getModifiers () {
82100 return super .getModifiers () & ~Modifier .NATIVE ;
83101 }
84102
85103 @ Override
86104 public StructuredGraph buildGraph (DebugContext debug , ResolvedJavaMethod method , HostedProviders providers , Purpose purpose ) {
87- UniverseMetaAccess metaAccess = (UniverseMetaAccess ) providers .getMetaAccess ();
88105 HostedGraphKit kit = new HostedGraphKit (debug , providers , method );
106+ boolean isDeoptTarget = (method instanceof SharedMethod ) && ((SharedMethod ) method ).isDeoptTarget ();
89107
90- ValueNode [] originalArgs = kit .loadArguments (method .toParameterTypes ()).toArray (ValueNode .EMPTY_ARRAY );
91-
92- ResolvedJavaType podType = metaAccess .lookupJavaType (Pod .class );
93- ValueNode podObject = kit .maybeCreateExplicitNullCheck (kit .createLoadField (originalArgs [0 ], findField (method .getDeclaringClass (), "pod" )));
94- ValueNode sizeWithoutRefMap = kit .createLoadField (podObject , findField (podType , "fieldsSizeWithoutRefMap" ));
95- ValueNode refMapArray = kit .createLoadField (podObject , findField (podType , "referenceMap" ));
96- ValueNode refMapLength = kit .append (new ArrayLengthNode (refMapArray ));
97- ValueNode hybridArrayLength = kit .append (AddNode .add (sizeWithoutRefMap , refMapLength ));
98-
99- PodFactory annotation = method .getDeclaringClass ().getAnnotation (PodFactory .class );
100- ResolvedJavaType podConcreteType = metaAccess .lookupJavaType (annotation .podClass ());
101- ResolvedJavaType elementType = metaAccess .lookupJavaType (byte .class );
102-
103- AbstractNewObjectNode instance = kit .append (new SubstrateNewHybridInstanceNode (podConcreteType , elementType , hybridArrayLength ));
104- kit .createInvokeWithExceptionAndUnwind (Pod .class , "initInstanceRefMap" , InvokeKind .Virtual , podObject , instance );
105-
108+ ResolvedJavaType factoryType = method .getDeclaringClass ();
109+ PodFactory annotation = factoryType .getAnnotation (PodFactory .class );
110+ ResolvedJavaType podConcreteType = kit .getMetaAccess ().lookupJavaType (annotation .podClass ());
111+ ResolvedJavaType elementType = kit .getMetaAccess ().lookupJavaType (byte .class );
106112 ResolvedJavaMethod targetCtor = null ;
107113 for (ResolvedJavaMethod ctor : podConcreteType .getSuperclass ().getDeclaredConstructors ()) {
108114 if (parameterTypesMatch (method , ctor )) {
@@ -112,12 +118,126 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method,
112118 }
113119 GraalError .guarantee (targetCtor != null , "Matching constructor not found: " + getSignature ());
114120
121+ /*
122+ * The graph must be safe for runtime compilation and so for compilation as a deoptimization
123+ * target. We must be careful to use values only from the frame state, so we keep the
124+ * allocated instance in a local and load it after each step during which a deopt can occur.
125+ */
126+ int instanceLocal = method .getSignature ().getParameterCount (true );
127+ int nextDeoptIndex = startMethod (kit , isDeoptTarget , 0 );
128+ instantiatePod (kit , factoryType , podConcreteType , elementType , instanceLocal );
129+ if (isAnnotationPresent (DeoptTest .class )) {
130+ kit .append (new TestDeoptimizeNode ());
131+ }
132+ nextDeoptIndex = initInstanceRefMap (kit , method , isDeoptTarget , nextDeoptIndex , instanceLocal );
133+ nextDeoptIndex = invokeConstructor (kit , method , isDeoptTarget , nextDeoptIndex , targetCtor , instanceLocal );
134+
135+ kit .createReturn (kit .loadLocal (instanceLocal , JavaKind .Object ), JavaKind .Object );
136+ return kit .finalizeGraph ();
137+ }
138+
139+ private static int startMethod (HostedGraphKit kit , boolean isDeoptTarget , int nextDeoptIndex ) {
140+ if (!isDeoptTarget ) {
141+ return nextDeoptIndex ;
142+ }
143+ FrameState initialState = kit .getGraph ().start ().stateAfter ();
144+ return appendDeoptWithExceptionUnwind (kit , initialState , initialState .bci , nextDeoptIndex );
145+ }
146+
147+ private static void instantiatePod (HostedGraphKit kit , ResolvedJavaType factoryType , ResolvedJavaType podConcreteType , ResolvedJavaType elementType , int instanceLocal ) {
148+ ResolvedJavaType podType = kit .getMetaAccess ().lookupJavaType (Pod .class );
149+ ValueNode pod = loadPod (kit , factoryType );
150+ ValueNode sizeWithoutRefMap = kit .createLoadField (pod , findField (podType , "fieldsSizeWithoutRefMap" ));
151+ ValueNode refMapArray = kit .createLoadField (pod , findField (podType , "referenceMap" ));
152+ ValueNode refMapLength = kit .append (new ArrayLengthNode (refMapArray ));
153+ ValueNode hybridArrayLength = kit .append (AddNode .add (sizeWithoutRefMap , refMapLength ));
154+ ValueNode instance = kit .append (new SubstrateNewHybridInstanceNode (podConcreteType , elementType , hybridArrayLength ));
155+ kit .storeLocal (instanceLocal , JavaKind .Object , instance );
156+ }
157+
158+ private static int initInstanceRefMap (HostedGraphKit kit , ResolvedJavaMethod method , boolean isDeoptTarget , int nextDeoptIndex , int instanceLocal ) {
159+ ValueNode instance = kit .loadLocal (instanceLocal , JavaKind .Object );
160+ ResolvedJavaMethod initInstanceRefMap = kit .findMethod (Pod .class , "initInstanceRefMap" , false );
161+ ValueNode pod = loadPod (kit , method .getDeclaringClass ());
162+ return invokeWithDeoptAndExceptionUnwind (kit , isDeoptTarget , nextDeoptIndex , initInstanceRefMap , InvokeKind .Virtual , pod , instance );
163+ }
164+
165+ private static int invokeConstructor (HostedGraphKit kit , ResolvedJavaMethod method , boolean isDeoptTarget , int nextDeoptIndex , ResolvedJavaMethod targetCtor , int instanceLocal ) {
166+ ValueNode instance = kit .loadLocal (instanceLocal , JavaKind .Object );
167+ ValueNode [] originalArgs = kit .loadArguments (method .toParameterTypes ()).toArray (ValueNode .EMPTY_ARRAY );
115168 ValueNode [] invokeArgs = Arrays .copyOf (originalArgs , originalArgs .length );
116169 invokeArgs [0 ] = instance ;
117- kit .createInvokeWithExceptionAndUnwind (targetCtor , InvokeKind .Special , kit .getFrameState (), kit .bci (), invokeArgs );
170+ return invokeWithDeoptAndExceptionUnwind (kit , isDeoptTarget , nextDeoptIndex , targetCtor , InvokeKind .Special , invokeArgs );
171+ }
118172
119- kit .createReturn (instance , instance .getStackKind ());
120- return kit .finalizeGraph ();
173+ private static ValueNode loadPod (HostedGraphKit kit , ResolvedJavaType declaringClass ) {
174+ ValueNode receiver = kit .loadLocal (0 , JavaKind .Object );
175+ return kit .maybeCreateExplicitNullCheck (kit .createLoadField (receiver , findField (declaringClass , "pod" )));
176+ }
177+
178+ /** @see com.oracle.svm.hosted.phases.HostedGraphBuilderPhase */
179+ private static int invokeWithDeoptAndExceptionUnwind (HostedGraphKit kit , boolean isDeoptTarget , int initialNextDeoptIndex , ResolvedJavaMethod target , InvokeKind invokeKind , ValueNode ... args ) {
180+ InvokeWithExceptionNode invoke = kit .startInvokeWithException (target , invokeKind , kit .getFrameState (), kit .bci (), args );
181+ kit .exceptionPart ();
182+ ExceptionObjectNode exception = kit .exceptionObject ();
183+
184+ if (!isDeoptTarget ) {
185+ kit .append (new UnwindNode (exception ));
186+ kit .endInvokeWithException ();
187+ return initialNextDeoptIndex ;
188+ }
189+
190+ int nextDeoptIndex = initialNextDeoptIndex ;
191+
192+ // Exception during invoke
193+
194+ var exceptionDeopt = kit .add (new DeoptEntryNode ());
195+ exceptionDeopt .setStateAfter (exception .stateAfter ().duplicate ());
196+ var exceptionDeoptBegin = kit .add (new DeoptEntryBeginNode ());
197+ int exceptionDeoptIndex = nextDeoptIndex ++;
198+ ValueNode exceptionProxy = createDeoptProxy (kit , exceptionDeoptIndex , exceptionDeopt , exception );
199+ var unwind = kit .append (new UnwindNode (exceptionProxy ));
200+ exception .setNext (exceptionDeopt );
201+ exceptionDeopt .setNext (exceptionDeoptBegin );
202+ exceptionDeoptBegin .setNext (unwind );
203+
204+ var exceptionDeoptExceptionEdge = kit .add (new UnreachableBeginNode ());
205+ exceptionDeoptExceptionEdge .setNext (kit .add (new LoweredDeadEndNode ()));
206+ exceptionDeopt .setExceptionEdge (exceptionDeoptExceptionEdge );
207+
208+ // Deopt entry after invoke without exception
209+
210+ kit .noExceptionPart ();
211+ nextDeoptIndex = appendDeoptWithExceptionUnwind (kit , invoke .stateAfter (), invoke .stateAfter ().bci , nextDeoptIndex );
212+ kit .endInvokeWithException ();
213+
214+ return nextDeoptIndex ;
215+ }
216+
217+ /** @see com.oracle.svm.hosted.phases.HostedGraphBuilderPhase */
218+ private static int appendDeoptWithExceptionUnwind (HostedGraphKit kit , FrameState state , int exceptionBci , int nextDeoptIndex ) {
219+ var entry = kit .add (new DeoptEntryNode ());
220+ entry .setStateAfter (state .duplicate ());
221+ var begin = kit .append (new DeoptEntryBeginNode ());
222+ ((FixedWithNextNode ) begin .predecessor ()).setNext (entry );
223+ entry .setNext (begin );
224+
225+ ExceptionObjectNode exception = kit .add (new ExceptionObjectNode (kit .getMetaAccess ()));
226+ entry .setExceptionEdge (exception );
227+ var exState = kit .getFrameState ().copy ();
228+ exState .clearStack ();
229+ exState .push (JavaKind .Object , exception );
230+ exState .setRethrowException (true );
231+ exception .setStateAfter (exState .create (exceptionBci , exception ));
232+ exception .setNext (kit .add (new UnwindNode (exception )));
233+
234+ // Ensure later nodes see values from potential deoptimization
235+ kit .getFrameState ().insertProxies (value -> createDeoptProxy (kit , nextDeoptIndex , entry , value ));
236+ return nextDeoptIndex + 1 ;
237+ }
238+
239+ private static ValueNode createDeoptProxy (HostedGraphKit kit , int nextDeoptIndex , FixedNode deoptTarget , ValueNode value ) {
240+ return kit .getGraph ().addOrUniqueWithInputs (DeoptProxyNode .create (value , deoptTarget , nextDeoptIndex ));
121241 }
122242
123243 private static boolean parameterTypesMatch (ResolvedJavaMethod method , ResolvedJavaMethod ctor ) {
0 commit comments