1111import org .jruby .ir .passes .CompilerPass ;
1212import org .jruby .ir .passes .CompilerPassScheduler ;
1313import org .jruby .ir .passes .DeadCodeElimination ;
14+ import org .jruby .ir .passes .OptimizeDynScopesPass ;
1415import org .jruby .ir .dataflow .analyses .StoreLocalVarPlacementProblem ;
1516import org .jruby .ir .dataflow .analyses .LiveVariablesProblem ;
1617import org .jruby .ir .passes .UnboxingPass ;
@@ -105,6 +106,9 @@ public abstract class IRScope implements ParseResult {
105106 /** Map of name -> dataflow problem */
106107 private Map <String , DataFlowProblem > dfProbs ;
107108
109+ /** What passes have been run on this scope? */
110+ private List <CompilerPass > executedPasses ;
111+
108112 private Instr [] linearizedInstrArray ;
109113 private List <BasicBlock > linearizedBBList ;
110114 private Map <Integer , Integer > rescueMap ;
@@ -163,6 +167,8 @@ protected IRScope(IRScope s, IRScope lexicalParent) {
163167 this .scopeId = globalScopeCount .getAndIncrement ();
164168 this .relinearizeCFG = false ;
165169
170+ this .executedPasses = new ArrayList <CompilerPass >();
171+
166172 setupLexicalContainment ();
167173 }
168174
@@ -208,6 +214,8 @@ public IRScope(IRManager manager, IRScope lexicalParent, String name,
208214 this .scopeId = globalScopeCount .getAndIncrement ();
209215 this .relinearizeCFG = false ;
210216
217+ this .executedPasses = new ArrayList <CompilerPass >();
218+
211219 setupLexicalContainment ();
212220 }
213221
@@ -538,6 +546,10 @@ private boolean isUnsafeScope() {
538546 return unsafeScope ;
539547 }
540548
549+ public List <CompilerPass > getExecutedPasses () {
550+ return executedPasses ;
551+ }
552+
541553 private void runCompilerPasses (List <CompilerPass > passes ) {
542554 // SSS FIXME: Why is this again? Document this weirdness!
543555 // Forcibly clear out the shared eval-scope variable allocator each time this method executes
@@ -561,40 +573,28 @@ private void runCompilerPasses(List<CompilerPass> passes) {
561573
562574 CompilerPassScheduler scheduler = getManager ().schedulePasses (passes );
563575 for (CompilerPass pass : scheduler ) {
564- if (pass .previouslyRun (this ) == null ) {
565- pass .run (this );
566- }
576+ pass .run (this );
567577 }
568578
569579 if (RubyInstanceConfig .IR_UNBOXING ) {
570580 (new UnboxingPass ()).run (this );
571581 }
572582 }
573583
574- private void runDeadCodeAndVarLoadStorePasses () {
575- // For scopes that don't require a dynamic scope,
576- // inline-add lvar loads/store to tmp-var loads/stores.
584+ private void optimizeSimpleScopes () {
585+ // For safe scopes that don't require a dynamic scope,
586+ // run DCE since the analysis is less likely to be
587+ // stymied by escaped bindings.
577588 if (!isUnsafeScope () && !flags .contains (REQUIRES_DYNSCOPE )) {
578- CompilerPass pass ;
579- pass = new DeadCodeElimination ();
580- if (pass .previouslyRun (this ) == null ) {
581- pass .run (this );
582- }
583-
584- // This will run the simplified version of the pass
585- // that doesn't require dataflow analysis and hence
586- // can run on closures independent of enclosing scopes.
587- pass = new AddLocalVarLoadStoreInstructions ();
588- if (pass .previouslyRun (this ) == null ) {
589- ((AddLocalVarLoadStoreInstructions )pass ).eliminateLocalVars (this );
590- setDataFlowSolution (StoreLocalVarPlacementProblem .NAME , new StoreLocalVarPlacementProblem ());
591- setDataFlowSolution (LiveVariablesProblem .NAME , null );
592- }
589+ (new DeadCodeElimination ()).run (this );
590+ (new OptimizeDynScopesPass ()).run (this );
593591 }
594592 }
595593
596- /** Run any necessary passes to get the IR ready for interpretation */
597- public synchronized Instr [] prepareForInterpretation (boolean isLambda ) {
594+ public void initScope (boolean isLambda ) {
595+ // Reset linearization, if any exists
596+ resetLinearizationData ();
597+
598598 // Build CFG and run compiler passes, if necessary
599599 if (getCFG () == null ) {
600600 buildCFG ();
@@ -615,41 +615,35 @@ public synchronized Instr[] prepareForInterpretation(boolean isLambda) {
615615 // Run DCE and var load/store passes where applicable
616616 // But, if we have been passed in a list of passes to run
617617 // on the commandline, skip this opt.
618- runDeadCodeAndVarLoadStorePasses ();
618+ optimizeSimpleScopes ();
619619 }
620+ }
621+
622+ /** Run any necessary passes to get the IR ready for interpretation */
623+ public synchronized Instr [] prepareForInterpretation (boolean isLambda ) {
624+ initScope (isLambda );
620625
621626 checkRelinearization ();
622627
623628 if (linearizedInstrArray != null ) return linearizedInstrArray ;
624629
630+ // System.out.println("-- passes run for: " + this + " = " + java.util.Arrays.toString(executedPasses.toArray()));
631+
625632 // Linearize CFG, etc.
626633 return prepareInstructions ();
627634 }
628635
629636 /* SSS FIXME: Do we need to synchronize on this? Cache this info in a scope field? */
630637 /** Run any necessary passes to get the IR ready for compilation */
631638 public synchronized List <BasicBlock > prepareForCompilation () {
632- // Reset linearization, since we will add JIT-specific flow and instrs
633- resetLinearizationData ();
634-
635- // Build CFG and run compiler passes, if necessary
636- if (getCFG () == null ) {
637- buildCFG ();
638- }
639-
640- // Add this always since we dont re-JIT a previously
641- // JIT-ted closure. But, check if there are other
642- // smarts available to us and eliminate adding this
643- // code to every closure there is.
639+ // For lambdas, we need to add a global ensure block to catch
640+ // uncaught breaks and throw a LocalJumpError.
644641 //
645- // Add a global ensure block to catch uncaught breaks
646- // and throw a LocalJumpError.
647- if (this instanceof IRClosure ) {
648- if (((IRClosure )this ).addGEBForUncaughtBreaks ()) {
649- resetState ();
650- computeScopeFlags ();
651- }
652- }
642+ // Since we dont re-JIT a previously JIT-ted closure,
643+ // mark all closures lambdas always. But, check if there are
644+ // other smarts available to us and eliminate adding
645+ // this code to every closure there is.
646+ initScope (this instanceof IRClosure );
653647
654648 runCompilerPasses (getManager ().getJITPasses (this ));
655649
@@ -1104,11 +1098,6 @@ public CFG cfg() {
11041098 return cfg ;
11051099 }
11061100
1107- public void resetDFProblemsState () {
1108- dfProbs = new HashMap <String , DataFlowProblem >();
1109- for (IRClosure c : nestedClosures ) c .resetDFProblemsState ();
1110- }
1111-
11121101 public void resetState () {
11131102 relinearizeCFG = true ;
11141103 linearizedInstrArray = null ;
@@ -1127,8 +1116,17 @@ public void resetState() {
11271116 flags .remove (CAN_RECEIVE_NONLOCAL_RETURNS );
11281117 rescueMap = null ;
11291118
1130- // Reset dataflow problems state
1131- resetDFProblemsState ();
1119+ // Invalidate compiler pass state.
1120+ //
1121+ // SSS FIXME: This is to get around concurrent-modification issues
1122+ // since CompilerPass.invalidate modifies this, but some passes
1123+ // cannot be invalidated.
1124+ int i = 0 ;
1125+ while (i < executedPasses .size ()) {
1126+ if (!executedPasses .get (i ).invalidate (this )) {
1127+ i ++;
1128+ }
1129+ }
11321130 }
11331131
11341132 public void inlineMethod (IRScope method , RubyModule implClass , int classToken , BasicBlock basicBlock , CallBase call , boolean cloneHost ) {
@@ -1145,10 +1143,6 @@ public void inlineMethod(IRScope method, RubyModule implClass, int classToken, B
11451143 }
11461144 }
11471145
1148- public void resetCFG () {
1149- cfg = null ;
1150- }
1151-
11521146 /* Record a begin block -- not all scope implementations can handle them */
11531147 public void recordBeginBlock (IRClosure beginBlockClosure ) {
11541148 throw new RuntimeException ("BEGIN blocks cannot be added to: " + this .getClass ().getName ());
0 commit comments