@@ -189,55 +189,69 @@ private boolean methodReturnsLocalPlayerDependentValue(ImMethod method) {
189189 return false ;
190190 }
191191
192- private void indexElement (Element element , ImFunction owner , Object controlContext ) {
193- indexedElements . add ( element );
192+ private record IndexTask (Element element , Object controlContext , boolean afterChildren ) {
193+ }
194194
195- Object branchControl = null ;
196- if (element instanceof ImIf ) {
197- ImIf ifStmt = (ImIf ) element ;
198- branchControl = new Fact (FactKind .CONTROL , ifStmt );
199- addDependency (ifStmt .getCondition (), branchControl );
200- addEnclosingControlDependency (controlContext , branchControl );
201- }
195+ private record ReturnTask (Element element , boolean afterChildren ) {
196+ }
202197
203- Object loopControl = null ;
204- if (element instanceof ImLoop ) {
205- ImLoop loop = (ImLoop ) element ;
206- loopControl = new Fact (FactKind .CONTROL , loop );
207- addEnclosingControlDependency (controlContext , loopControl );
208- addLoopExitDependencies (loop .getBody (), loopControl );
209- }
198+ private record LoopExitTask (Element element , boolean afterChildren ) {
199+ }
210200
211- if (element instanceof ImStmts ) {
212- indexStatementSequence ((ImStmts ) element , owner , controlContext );
213- return ;
214- }
201+ private void indexElement (Element root , ImFunction owner , Object controlContext ) {
202+ Deque <IndexTask > work = new ArrayDeque <>();
203+ work .addFirst (new IndexTask (root , controlContext , false ));
204+ while (!work .isEmpty ()) {
205+ IndexTask task = work .removeFirst ();
206+ Element element = task .element ();
207+ if (task .afterChildren ()) {
208+ indexElementAfterChildren (element , owner , task .controlContext ());
209+ continue ;
210+ }
215211
216- for (int i = 0 ; i < element .size (); i ++) {
217- Element child = element .get (i );
218- if (element instanceof ImOperatorCall
219- && ((ImOperatorCall ) element ).getOp ().isLazy ()
220- && child == ((ImOperatorCall ) element ).getArguments ()) {
221- indexShortCircuitArguments (
222- ((ImOperatorCall ) element ).getArguments (),
223- owner ,
224- controlContext );
225- addDependency (child , element );
212+ indexedElements .add (element );
213+ Object branchControl = null ;
214+ if (element instanceof ImIf ifStmt ) {
215+ branchControl = new Fact (FactKind .CONTROL , ifStmt );
216+ addDependency (ifStmt .getCondition (), branchControl );
217+ addEnclosingControlDependency (task .controlContext (), branchControl );
218+ }
219+
220+ Object loopControl = null ;
221+ if (element instanceof ImLoop loop ) {
222+ loopControl = new Fact (FactKind .CONTROL , loop );
223+ addEnclosingControlDependency (task .controlContext (), loopControl );
224+ addLoopExitDependencies (loop .getBody (), loopControl );
225+ }
226+
227+ if (element instanceof ImStmts statements ) {
228+ scheduleStatementSequence (statements , task .controlContext (), work );
226229 continue ;
227230 }
228- Object childControl = controlContext ;
229- if (element instanceof ImIf
230- && (child == ((ImIf ) element ).getThenBlock ()
231- || child == ((ImIf ) element ).getElseBlock ())) {
232- childControl = branchControl ;
233- } else if (element instanceof ImLoop
234- && child == ((ImLoop ) element ).getBody ()) {
235- childControl = loopControl ;
231+
232+ work .addFirst (new IndexTask (element , task .controlContext (), true ));
233+ for (int i = element .size () - 1 ; i >= 0 ; i --) {
234+ Element child = element .get (i );
235+ addDependency (child , element );
236+ if (element instanceof ImOperatorCall operator
237+ && operator .getOp ().isLazy ()
238+ && child == operator .getArguments ()) {
239+ scheduleShortCircuitArguments (operator .getArguments (), task .controlContext (), work );
240+ continue ;
241+ }
242+ Object childControl = task .controlContext ();
243+ if (element instanceof ImIf ifStmt
244+ && (child == ifStmt .getThenBlock () || child == ifStmt .getElseBlock ())) {
245+ childControl = branchControl ;
246+ } else if (element instanceof ImLoop loop && child == loop .getBody ()) {
247+ childControl = loopControl ;
248+ }
249+ work .addFirst (new IndexTask (child , childControl , false ));
236250 }
237- indexElement (child , owner , childControl );
238- addDependency (child , element );
239251 }
252+ }
240253
254+ private void indexElementAfterChildren (Element element , ImFunction owner , Object controlContext ) {
241255 if (element instanceof ImVarAccess ) {
242256 addDependency (variableFact (((ImVarAccess ) element ).getVar ()), element );
243257 } else if (element instanceof ImVarArrayAccess ) {
@@ -273,13 +287,14 @@ private void indexElement(Element element, ImFunction owner, Object controlConte
273287 }
274288 }
275289
276- private void indexStatementSequence (ImStmts statements ,
277- ImFunction owner ,
278- Object controlContext ) {
290+ private void scheduleStatementSequence (ImStmts statements ,
291+ Object controlContext ,
292+ Deque <IndexTask > work ) {
293+ List <IndexTask > tasks = new ArrayList <>(statements .size ());
279294 Object continuationControl = controlContext ;
280295 for (ImStmt statement : statements ) {
281- indexElement (statement , owner , continuationControl );
282296 addDependency (statement , statements );
297+ tasks .add (new IndexTask (statement , continuationControl , false ));
283298
284299 if (containsFunctionReturn (statement )) {
285300 Fact followingStatementControl =
@@ -291,36 +306,60 @@ private void indexStatementSequence(ImStmts statements,
291306 continuationControl = followingStatementControl ;
292307 }
293308 }
309+ for (int i = tasks .size () - 1 ; i >= 0 ; i --) {
310+ work .addFirst (tasks .get (i ));
311+ }
294312 }
295313
296- private boolean containsFunctionReturn (Element element ) {
297- Boolean cached = containsReturnCache .get (element );
314+ private boolean containsFunctionReturn (Element root ) {
315+ Boolean cached = containsReturnCache .get (root );
298316 if (cached != null ) {
299317 return cached ;
300318 }
301- if (element instanceof ImReturn ) {
302- containsReturnCache .put (element , true );
303- return true ;
304- }
305- for (int i = 0 ; i < element .size (); i ++) {
306- if (containsFunctionReturn (element .get (i ))) {
319+ Deque <ReturnTask > work = new ArrayDeque <>();
320+ work .addFirst (new ReturnTask (root , false ));
321+ while (!work .isEmpty ()) {
322+ ReturnTask task = work .removeFirst ();
323+ Element element = task .element ();
324+ if (containsReturnCache .containsKey (element )) {
325+ continue ;
326+ }
327+ if (element instanceof ImReturn ) {
307328 containsReturnCache .put (element , true );
308- return true ;
329+ continue ;
330+ }
331+ if (!task .afterChildren ()) {
332+ work .addFirst (new ReturnTask (element , true ));
333+ for (int i = element .size () - 1 ; i >= 0 ; i --) {
334+ Element child = element .get (i );
335+ if (!containsReturnCache .containsKey (child )) {
336+ work .addFirst (new ReturnTask (child , false ));
337+ }
338+ }
339+ continue ;
309340 }
341+ boolean containsReturn = false ;
342+ for (int i = 0 ; i < element .size (); i ++) {
343+ if (Boolean .TRUE .equals (containsReturnCache .get (element .get (i )))) {
344+ containsReturn = true ;
345+ break ;
346+ }
347+ }
348+ containsReturnCache .put (element , containsReturn );
310349 }
311- containsReturnCache .put (element , false );
312- return false ;
350+ return Boolean .TRUE .equals (containsReturnCache .get (root ));
313351 }
314352
315- private void indexShortCircuitArguments (ImExprs arguments ,
316- ImFunction owner ,
317- Object controlContext ) {
353+ private void scheduleShortCircuitArguments (ImExprs arguments ,
354+ Object controlContext ,
355+ Deque < IndexTask > work ) {
318356 indexedElements .add (arguments );
357+ List <IndexTask > tasks = new ArrayList <>(arguments .size ());
319358 Object operandControl = controlContext ;
320359 for (int i = 0 ; i < arguments .size (); i ++) {
321360 ImExpr argument = arguments .get (i );
322- indexElement (argument , owner , operandControl );
323361 addDependency (argument , arguments );
362+ tasks .add (new IndexTask (argument , operandControl , false ));
324363
325364 if (i + 1 < arguments .size ()) {
326365 Fact followingOperandControl =
@@ -332,6 +371,9 @@ private void indexShortCircuitArguments(ImExprs arguments,
332371 operandControl = followingOperandControl ;
333372 }
334373 }
374+ for (int i = tasks .size () - 1 ; i >= 0 ; i --) {
375+ work .addFirst (tasks .get (i ));
376+ }
335377 }
336378
337379 private void indexFunctionCall (ImFunctionCall call , ImFunction owner , Object controlContext ) {
@@ -402,22 +444,40 @@ private void addEnclosingControlDependency(Object controlContext, Object depende
402444 }
403445 }
404446
405- private boolean addLoopExitDependencies (Element element , Object loopControl ) {
406- if (element instanceof ImExitwhen ) {
407- addDependency (((ImExitwhen ) element ).getCondition (), loopControl );
408- return true ;
409- } else if (element instanceof ImLoop || element instanceof ImVarargLoop ) {
410- return false ;
411- }
447+ private boolean addLoopExitDependencies (Element root , Object loopControl ) {
448+ Map <Element , Boolean > containsExit = new IdentityHashMap <>();
449+ Deque <LoopExitTask > work = new ArrayDeque <>();
450+ work .addFirst (new LoopExitTask (root , false ));
451+ while (!work .isEmpty ()) {
452+ LoopExitTask task = work .removeFirst ();
453+ Element element = task .element ();
454+ if (element instanceof ImExitwhen exitwhen ) {
455+ addDependency (exitwhen .getCondition (), loopControl );
456+ containsExit .put (element , true );
457+ continue ;
458+ }
459+ if (element instanceof ImLoop || element instanceof ImVarargLoop ) {
460+ containsExit .put (element , false );
461+ continue ;
462+ }
463+ if (!task .afterChildren ()) {
464+ work .addFirst (new LoopExitTask (element , true ));
465+ for (int i = element .size () - 1 ; i >= 0 ; i --) {
466+ work .addFirst (new LoopExitTask (element .get (i ), false ));
467+ }
468+ continue ;
469+ }
412470
413- boolean containsExit = false ;
414- for (int i = 0 ; i < element .size (); i ++) {
415- containsExit |= addLoopExitDependencies (element .get (i ), loopControl );
416- }
417- if (containsExit && element instanceof ImIf ) {
418- addDependency (((ImIf ) element ).getCondition (), loopControl );
471+ boolean elementContainsExit = false ;
472+ for (int i = 0 ; i < element .size (); i ++) {
473+ elementContainsExit |= Boolean .TRUE .equals (containsExit .get (element .get (i )));
474+ }
475+ if (elementContainsExit && element instanceof ImIf ifStmt ) {
476+ addDependency (ifStmt .getCondition (), loopControl );
477+ }
478+ containsExit .put (element , elementContainsExit );
419479 }
420- return containsExit ;
480+ return Boolean . TRUE . equals ( containsExit . get ( root )) ;
421481 }
422482
423483 private boolean collectMethodImplementations (ImMethod method ,
0 commit comments