1 package polyglot.frontend; 2 3 import polyglot.ast.*; 4 import polyglot.types.*; 5 import polyglot.util.*; 6 import polyglot.visit.*; 7 import polyglot.main.Options; 8 import polyglot.main.Report; 9 10 import java.io.*; 11 import java.util.*; 12 13 16 public abstract class AbstractExtensionInfo implements ExtensionInfo { 17 protected Compiler compiler; 18 private Options options; 19 protected TypeSystem ts = null; 20 protected NodeFactory nf = null; 21 protected SourceLoader source_loader = null; 22 protected TargetFactory target_factory = null; 23 protected Stats stats; 24 25 28 protected LinkedList worklist; 29 30 36 protected Map jobs; 37 38 protected static final Object COMPLETED_JOB = "COMPLETED JOB"; 39 40 41 protected Job currentJob; 42 43 public Options getOptions() { 44 if (this.options == null) { 45 this.options = createOptions(); 46 } 47 return options; 48 } 49 50 protected Options createOptions() { 51 return new Options(this); 52 } 53 54 55 public Stats getStats() { 56 if (this.stats == null) { 57 this.stats = new Stats(this); 58 } 59 return stats; 60 } 61 62 public Compiler compiler() { 63 return compiler; 64 } 65 66 public void initCompiler(Compiler compiler) { 67 this.compiler = compiler; 68 jobs = new HashMap(); 69 worklist = new LinkedList(); 70 71 compiler.addExtension(this); 73 74 currentJob = null; 75 76 typeSystem(); 78 nodeFactory(); 79 80 initTypeSystem(); 81 } 82 83 protected abstract void initTypeSystem(); 84 85 99 public boolean runToCompletion() { 100 boolean okay = true; 101 102 while (okay && ! worklist.isEmpty()) { 103 SourceJob job = selectJobFromWorklist(); 104 105 if (Report.should_report(Report.frontend, 1)) { 106 Report.report(1, "Running job " + job); 107 } 108 109 okay &= runAllPasses(job); 110 111 if (job.completed()) { 112 jobs.put(job.source(), COMPLETED_JOB); 115 116 if (Report.should_report(Report.frontend, 1)) { 117 Report.report(1, "Completed job " + job); 118 } 119 } 120 else { 121 if (Report.should_report(Report.frontend, 1)) { 124 Report.report(1, "Failed to complete job " + job); 125 } 126 worklist.add(job); 127 } 128 } 129 130 if (Report.should_report(Report.frontend, 1)) 131 Report.report(1, "Finished all passes -- " + 132 (okay ? "okay" : "failed")); 133 134 return okay; 135 } 136 137 142 protected SourceJob selectJobFromWorklist() { 143 return (SourceJob)worklist.remove(0); 144 } 145 146 150 public boolean readSource(FileSource source) { 151 SourceJob job = addJob(source); 154 155 if (job == null) { 156 return true; 159 } 160 161 Pass.ID barrier; 164 165 if (currentJob != null) { 166 if (currentJob.sourceJob().lastBarrier() == null) { 167 throw new InternalCompilerError("A Source Job which has " + 168 "not reached a barrier cannot read another " + 169 "source file."); 170 } 171 172 barrier = currentJob.sourceJob().lastBarrier().id(); 173 } 174 else { 175 barrier = Pass.FIRST_BARRIER; 176 } 177 178 return runToPass(job, barrier) && runToPass(job, Pass.FIRST_BARRIER); 183 } 184 185 188 public boolean runAllPasses(Job job) { 189 List pending = job.pendingPasses(); 190 191 if (!pending.isEmpty()) { 193 Pass lastPass = (Pass)pending.get(pending.size() - 1); 194 return runToPass(job, lastPass); 195 } 196 197 return true; 198 } 199 200 203 public boolean runToPass(Job job, Pass.ID goal) { 204 if (Report.should_report(Report.frontend, 1)) 205 Report.report(1, "Running " + job + " to pass named " + goal); 206 207 if (job.completed(goal)) { 208 return true; 209 } 210 211 Pass pass = job.passByID(goal); 212 213 return runToPass(job, pass); 214 } 215 216 219 public boolean runToPass(Job job, Pass goal) { 220 if (Report.should_report(Report.frontend, 1)) 221 Report.report(1, "Running " + job + " to pass " + goal); 222 223 while (! job.pendingPasses().isEmpty()) { 224 Pass pass = (Pass) job.pendingPasses().get(0); 225 226 try { 227 runPass(job, pass); 228 } 229 catch (CyclicDependencyException e) { 230 job.finishPass(pass, false); 232 } 233 234 if (pass == goal) { 235 break; 236 } 237 } 238 239 if (job.completed()) { 240 if (Report.should_report(Report.frontend, 1)) 241 Report.report(1, "Job " + job + " completed"); 242 } 243 244 return job.status(); 245 } 246 247 253 protected void runPass(Job job, Pass pass) throws CyclicDependencyException 254 { 255 try { 259 enforceInvariants(job, pass); 260 } 261 catch (CyclicDependencyException e) { 262 return; 268 } 269 270 if (getOptions().disable_passes.contains(pass.name())) { 271 if (Report.should_report(Report.frontend, 1)) 272 Report.report(1, "Skipping pass " + pass); 273 job.finishPass(pass, true); 274 return; 275 } 276 277 if (Report.should_report(Report.frontend, 1)) 278 Report.report(1, "Trying to run pass " + pass + " in " + job); 279 280 if (job.isRunning()) { 281 throw new CyclicDependencyException(job + 283 " cannot reach pass " + 284 pass); 285 } 286 287 pass.resetTimers(); 288 289 boolean result = false; 290 if (job.status()) { 291 Job oldCurrentJob = this.currentJob; 292 this.currentJob = job; 293 Report.should_report.push(pass.name()); 294 295 Pass oldPass = oldCurrentJob != null 297 ? oldCurrentJob.runningPass() 298 : null; 299 300 if (oldPass != null) { 301 oldPass.toggleTimers(true); 302 } 303 304 job.setRunningPass(pass); 305 pass.toggleTimers(false); 306 307 result = pass.run(); 308 309 pass.toggleTimers(false); 310 job.setRunningPass(null); 311 312 Report.should_report.pop(); 313 this.currentJob = oldCurrentJob; 314 315 if (oldPass != null) { 317 oldPass.toggleTimers(true); 318 } 319 320 if (getOptions().print_ast.contains(pass.name())) { 322 System.err.println("--------------------------------" + 323 "--------------------------------"); 324 System.err.println("Pretty-printing AST for " + job + 325 " after " + pass.name()); 326 327 PrettyPrinter pp = new PrettyPrinter(); 328 pp.printAst(job.ast(), new CodeWriter(System.err, 78)); 329 } 330 331 if (getOptions().dump_ast.contains(pass.name())) { 333 System.err.println("--------------------------------" + 334 "--------------------------------"); 335 System.err.println("Dumping AST for " + job + 336 " after " + pass.name()); 337 338 NodeVisitor dumper = 339 new DumpAst(new CodeWriter(System.err, 78)); 340 dumper = dumper.begin(); 341 job.ast().visit(dumper); 342 dumper.finish(); 343 } 344 345 350 } 352 353 Stats stats = getStats(); 354 stats.accumPassTimes(pass.id(), pass.inclusiveTime(), 355 pass.exclusiveTime()); 356 357 if (Report.should_report(Report.time, 2)) { 358 Report.report(2, "Finished " + pass + 359 " status=" + str(result) + " inclusive_time=" + 360 pass.inclusiveTime() + " exclusive_time=" + 361 pass.exclusiveTime()); 362 } 363 else if (Report.should_report(Report.frontend, 1)) { 364 Report.report(1, "Finished " + pass + 365 " status=" + str(result)); 366 } 367 368 job.finishPass(pass, result); 369 } 370 371 378 protected void enforceInvariants(Job job, Pass pass) throws CyclicDependencyException { 379 SourceJob srcJob = job.sourceJob(); 380 if (srcJob == null) { 381 return; 382 } 383 384 BarrierPass lastBarrier = srcJob.lastBarrier(); 385 if (lastBarrier != null) { 386 List allDependentSrcs = new ArrayList(srcJob.dependencies()); 393 Iterator i = allDependentSrcs.iterator(); 394 while (i.hasNext()) { 395 Source s = (Source)i.next(); 396 Object o = jobs.get(s); 397 if (o == COMPLETED_JOB) continue; 398 if (o == null) { 399 throw new InternalCompilerError("Unknown source " + s); 400 } 401 SourceJob sj = (SourceJob)o; 402 if (sj.pending(lastBarrier.id())) { 403 if (Report.should_report(Report.frontend, 3)) { 408 Report.report(3, "Running " + sj + 409 " to " + lastBarrier.id() + " for " + srcJob); 410 } 411 runToPass(sj, lastBarrier.id()); 412 } 413 } 414 } 415 416 if (pass instanceof GlobalBarrierPass) { 417 420 LinkedList barrierWorklist = new LinkedList(jobs.values()); 424 425 while (! barrierWorklist.isEmpty()) { 426 Object o = barrierWorklist.removeFirst(); 427 if (o == COMPLETED_JOB) continue; 428 SourceJob sj = (SourceJob)o; 429 if (sj.completed(pass.id()) || 430 sj.nextPass() == sj.passByID(pass.id())) { 431 continue; 435 } 436 437 Pass beforeGlobal = sj.getPreviousTo(pass.id()); 442 if (Report.should_report(Report.frontend, 3)) { 443 Report.report(3, "Running " + sj + 444 " to " + beforeGlobal.id() + " for " + srcJob); 445 } 446 447 while (! sj.pendingPasses().isEmpty()) { 451 Pass p = (Pass) sj.pendingPasses().get(0); 452 453 runPass(sj, p); 454 455 if (p == beforeGlobal) { 456 break; 457 } 458 } 459 } 460 } 461 } 462 463 private static String str(boolean okay) { 464 if (okay) { 465 return "done"; 466 } 467 else { 468 return "failed"; 469 } 470 } 471 472 477 public String [] fileExtensions() { 478 String [] sx = getOptions() == null ? null : getOptions().source_ext; 479 480 if (sx == null) { 481 sx = defaultFileExtensions(); 482 } 483 484 if (sx.length == 0) { 485 return defaultFileExtensions(); 486 } 487 488 return sx; 489 } 490 491 492 public String [] defaultFileExtensions() { 493 String ext = defaultFileExtension(); 494 return new String [] { ext }; 495 } 496 497 498 public SourceLoader sourceLoader() { 499 if (source_loader == null) { 500 source_loader = new SourceLoader(this, getOptions().source_path); 501 } 502 503 return source_loader; 504 } 505 506 507 public TargetFactory targetFactory() { 508 if (target_factory == null) { 509 target_factory = new TargetFactory(getOptions().output_directory, 510 getOptions().output_ext, 511 getOptions().output_stdout); 512 } 513 514 return target_factory; 515 } 516 517 518 protected abstract TypeSystem createTypeSystem(); 519 520 521 public TypeSystem typeSystem() { 522 if (ts == null) { 523 ts = createTypeSystem(); 524 } 525 return ts; 526 } 527 528 529 protected abstract NodeFactory createNodeFactory(); 530 531 532 public NodeFactory nodeFactory() { 533 if (nf == null) { 534 nf = createNodeFactory(); 535 } 536 return nf; 537 } 538 539 544 public JobExt jobExt() { 545 return null; 546 } 547 548 551 public void addDependencyToCurrentJob(Source s) { 552 if (s == null) 553 return; 554 if (currentJob != null) { 555 Object o = jobs.get(s); 556 if (o != COMPLETED_JOB) { 557 if (Report.should_report(Report.frontend, 2)) { 558 Report.report(2, "Adding dependency from " + 559 currentJob.source() + " to " + 560 s); 561 } 562 currentJob.sourceJob().addDependency(s); 563 } 564 } 565 else { 566 throw new InternalCompilerError("No current job!"); 567 } 568 } 569 570 577 public SourceJob addJob(Source source) { 578 return addJob(source, null); 579 } 580 581 589 public SourceJob addJob(Source source, Node ast) { 590 Object o = jobs.get(source); 591 SourceJob job = null; 592 if (o == COMPLETED_JOB) { 593 return null; 596 } 597 else if (o == null) { 598 600 job = this.createSourceJob(source, ast); 601 602 jobs.put(source, job); 604 worklist.addLast(job); 605 606 if (Report.should_report(Report.frontend, 3)) { 607 Report.report(3, "Adding job for " + source + " at the " + 608 "request of job " + currentJob); 609 } 610 } 611 else { 612 job = (SourceJob)o; 613 } 614 615 if (currentJob instanceof SourceJob) { 618 ((SourceJob)currentJob).addDependency(source); 619 } 620 621 return job; 622 } 623 624 628 protected SourceJob createSourceJob(Source source, Node ast) { 629 return new SourceJob(this, jobExt(), source, ast); 630 } 631 632 643 protected Job createJob(Node ast, Context context, Job outer, Pass.ID begin, Pass.ID end) { 644 return new InnerJob(this, jobExt(), ast, context, outer, begin, end); 645 } 646 647 660 public Job spawnJob(Context c, Node ast, Job outerJob, 661 Pass.ID begin, Pass.ID end) { 662 Job j = createJob(ast, c, outerJob, begin, end); 663 664 if (Report.should_report(Report.frontend, 1)) 665 Report.report(1, this +" spawning " + j); 666 667 runAllPasses(j); 669 670 return j; 672 } 673 674 675 public abstract Parser parser(Reader reader, FileSource source, 676 ErrorQueue eq); 677 678 682 public void replacePass(List passes, Pass.ID id, List newPasses) { 683 for (ListIterator i = passes.listIterator(); i.hasNext(); ) { 684 Pass p = (Pass) i.next(); 685 686 if (p.id() == id) { 687 if (p instanceof BarrierPass) { 688 throw new InternalCompilerError("Cannot replace a barrier pass."); 689 } 690 691 i.remove(); 692 693 for (Iterator j = newPasses.iterator(); j.hasNext(); ) { 694 i.add(j.next()); 695 } 696 697 return; 698 } 699 } 700 701 throw new InternalCompilerError("Pass " + id + " not found."); 702 } 703 704 707 public void removePass(List passes, Pass.ID id) { 708 for (ListIterator i = passes.listIterator(); i.hasNext(); ) { 709 Pass p = (Pass) i.next(); 710 711 if (p.id() == id) { 712 if (p instanceof BarrierPass) { 713 throw new InternalCompilerError("Cannot remove a barrier pass."); 714 } 715 716 i.remove(); 717 return; 718 } 719 } 720 721 throw new InternalCompilerError("Pass " + id + " not found."); 722 } 723 724 728 public void beforePass(List passes, Pass.ID id, List newPasses) { 729 for (ListIterator i = passes.listIterator(); i.hasNext(); ) { 730 Pass p = (Pass) i.next(); 731 732 if (p.id() == id) { 733 i.previous(); 735 736 for (Iterator j = newPasses.iterator(); j.hasNext(); ) { 737 i.add(j.next()); 738 } 739 740 return; 741 } 742 } 743 744 throw new InternalCompilerError("Pass " + id + " not found."); 745 } 746 747 751 public void afterPass(List passes, Pass.ID id, List newPasses) { 752 for (ListIterator i = passes.listIterator(); i.hasNext(); ) { 753 Pass p = (Pass) i.next(); 754 755 if (p.id() == id) { 756 for (Iterator j = newPasses.iterator(); j.hasNext(); ) { 757 i.add(j.next()); 758 } 759 760 return; 761 } 762 } 763 764 throw new InternalCompilerError("Pass " + id + " not found."); 765 } 766 767 771 public void replacePass(List passes, Pass.ID id, Pass pass) { 772 replacePass(passes, id, Collections.singletonList(pass)); 773 } 774 775 779 public void beforePass(List passes, Pass.ID id, Pass pass) { 780 beforePass(passes, id, Collections.singletonList(pass)); 781 } 782 783 787 public void afterPass(List passes, Pass.ID id, Pass pass) { 788 afterPass(passes, id, Collections.singletonList(pass)); 789 } 790 791 794 public abstract List passes(Job job); 795 796 800 public List passes(Job job, Pass.ID begin, Pass.ID end) { 801 List l = passes(job); 802 Pass p = null; 803 804 Iterator i = l.iterator(); 805 806 while (i.hasNext()) { 807 p = (Pass) i.next(); 808 if (begin == p.id()) break; 809 if (! (p instanceof BarrierPass)) i.remove(); 810 } 811 812 while (p.id() != end && i.hasNext()) { 813 p = (Pass) i.next(); 814 } 815 816 while (i.hasNext()) { 817 p = (Pass) i.next(); 818 i.remove(); 819 } 820 821 return l; 822 } 823 824 public String toString() { 825 return getClass().getName() + " worklist=" + worklist; 826 } 827 } 828 | Popular Tags |