001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.mmtk.plan; 014 015import org.mmtk.utility.Log; 016import org.mmtk.utility.options.Options; 017import org.mmtk.utility.statistics.Timer; 018import org.mmtk.vm.VM; 019 020import org.vmmagic.pragma.*; 021 022/** 023 * A garbage collection proceeds as a sequence of phases. Each 024 * phase is either simple (singular) or complex (an array).<p> 025 * 026 * The context an individual phase executes in may be global, mutator, 027 * or collector.<p> 028 * 029 * Phases are executed within a stack and all synchronization between 030 * parallel GC threads is managed from within this class. 031 * 032 * @see MutatorContext#collectionPhase 033 */ 034@Uninterruptible 035public abstract class Phase { 036 /*********************************************************************** 037 * 038 * Phase allocation and storage. 039 */ 040 041 /** The maximum number of phases */ 042 private static final int MAX_PHASES = 64; 043 /** The array of phase instances. Zero is unused. */ 044 private static final Phase[] phases = new Phase[MAX_PHASES]; 045 /** The id to be allocated for the next phase */ 046 private static short nextPhaseId = 1; 047 048 /** Run the phase globally. */ 049 protected static final short SCHEDULE_GLOBAL = 1; 050 /** Run the phase on collectors. */ 051 protected static final short SCHEDULE_COLLECTOR = 2; 052 /** Run the phase on mutators. */ 053 protected static final short SCHEDULE_MUTATOR = 3; 054 /** Run this phase concurrently with the mutators */ 055 protected static final short SCHEDULE_CONCURRENT = 4; 056 /** Don't run this phase. */ 057 protected static final short SCHEDULE_PLACEHOLDER = 100; 058 /** This is a complex phase. */ 059 protected static final short SCHEDULE_COMPLEX = 101; 060 061 /** 062 * Retrieve a phase by the unique phase identifier. 063 * 064 * @param id The phase identifier. 065 * @return The Phase instance. 066 */ 067 public static Phase getPhase(short id) { 068 if (VM.VERIFY_ASSERTIONS) { 069 VM.assertions._assert(id < nextPhaseId, "Phase ID unknown"); 070 VM.assertions._assert(phases[id] != null, "Uninitialised phase"); 071 } 072 return phases[id]; 073 } 074 075 /** 076 * @param scheduledPhase an encoded phase 077 * @return the phase id component of an encoded phase 078 */ 079 protected static short getPhaseId(int scheduledPhase) { 080 short phaseId = (short)(scheduledPhase & 0x0000FFFF); 081 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(phaseId > 0); 082 return phaseId; 083 } 084 085 /** 086 * @param phaseId The unique phase identifier. 087 * @return The name of the phase. 088 */ 089 public static String getName(short phaseId) { 090 return phases[phaseId].name; 091 } 092 093 /** 094 * @param scheduledPhase an encoded phase 095 * @return the ordering component of an encoded phase 096 */ 097 protected static short getSchedule(int scheduledPhase) { 098 short ordering = (short)((scheduledPhase >> 16) & 0x0000FFFF); 099 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(ordering > 0); 100 return ordering; 101 } 102 103 /** 104 * @param ordering the ordering component of a phase 105 * @return human-readable name for the schedule 106 */ 107 protected static String getScheduleName(short ordering) { 108 switch (ordering) { 109 case SCHEDULE_GLOBAL: return "Global"; 110 case SCHEDULE_COLLECTOR: return "Collector"; 111 case SCHEDULE_MUTATOR: return "Mutator"; 112 case SCHEDULE_CONCURRENT: return "Concurrent"; 113 case SCHEDULE_PLACEHOLDER: return "Placeholder"; 114 case SCHEDULE_COMPLEX: return "Complex"; 115 default: return "UNKNOWN!"; 116 } 117 } 118 119 /** 120 * Constructs a phase. 121 * 122 * @param name Display name of the phase 123 * @return the id of the simple phase 124 */ 125 @Interruptible 126 public static short createSimple(String name) { 127 return new SimplePhase(name).getId(); 128 } 129 130 /** 131 * Constructs a phase, re-using a specified timer. 132 * 133 * @param name Display name of the phase 134 * @param timer the time to re-use 135 * @return the id of the simple phase 136 */ 137 @Interruptible 138 public static short createSimple(String name, Timer timer) { 139 return new SimplePhase(name, timer).getId(); 140 } 141 142 /** 143 * Constructs a complex phase. 144 * 145 * @param name Display name of the phase 146 * @param scheduledPhases The phases in this complex phase. 147 * @return the phase's id 148 */ 149 @Interruptible 150 public static short createComplex(String name,int... scheduledPhases) { 151 return new ComplexPhase(name, scheduledPhases).getId(); 152 } 153 154 /** 155 * Constructs a complex phase, re-using a specified timer. 156 * 157 * @param name Display name of the phase 158 * @param timer Timer for this phase to contribute to 159 * @param scheduledPhases The phases in this complex phase. 160 * @return the phase's id 161 */ 162 @Interruptible 163 public static short createComplex(String name, Timer timer, int... scheduledPhases) { 164 return new ComplexPhase(name, timer, scheduledPhases).getId(); 165 } 166 167 /** 168 * Constructs a phase. 169 * 170 * @param name Display name of the phase 171 * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world collection 172 * @return the phase's id 173 */ 174 @Interruptible 175 public static final short createConcurrent(String name, int atomicScheduledPhase) { 176 return new ConcurrentPhase(name, atomicScheduledPhase).getId(); 177 } 178 179 /** 180 * Construct a phase, re-using a specified timer. 181 * 182 * @param name Display name of the phase 183 * @param timer Timer for this phase to contribute to 184 * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world collection 185 * @return the phase's id 186 */ 187 @Interruptible 188 public static final short createConcurrent(String name, Timer timer, int atomicScheduledPhase) { 189 return new ConcurrentPhase(name, timer, atomicScheduledPhase).getId(); 190 } 191 192 /** 193 * Take the passed phase and return an encoded phase to 194 * run that phase as a complex phase. 195 * 196 * @param phaseId The phase to run as complex 197 * @return The encoded phase value. 198 */ 199 public static int scheduleComplex(short phaseId) { 200 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof ComplexPhase); 201 return (SCHEDULE_COMPLEX << 16) + phaseId; 202 } 203 204 /** 205 * Take the passed phase and return an encoded phase to 206 * run that phase as a concurrent phase. 207 * 208 * @param phaseId The phase to run as concurrent 209 * @return The encoded phase value. 210 */ 211 public static int scheduleConcurrent(short phaseId) { 212 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof ConcurrentPhase); 213 return (SCHEDULE_CONCURRENT << 16) + phaseId; 214 } 215 216 /** 217 * Take the passed phase and return an encoded phase to 218 * run that phase in a global context; 219 * 220 * @param phaseId The phase to run globally 221 * @return The encoded phase value. 222 */ 223 public static int scheduleGlobal(short phaseId) { 224 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase); 225 return (SCHEDULE_GLOBAL << 16) + phaseId; 226 } 227 228 /** 229 * Take the passed phase and return an encoded phase to 230 * run that phase in a collector context; 231 * 232 * @param phaseId The phase to run on collectors 233 * @return The encoded phase value. 234 */ 235 public static int scheduleCollector(short phaseId) { 236 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase); 237 return (SCHEDULE_COLLECTOR << 16) + phaseId; 238 } 239 240 /** 241 * Take the passed phase and return an encoded phase to 242 * run that phase in a mutator context; 243 * 244 * @param phaseId The phase to run on mutators 245 * @return The encoded phase value. 246 */ 247 public static int scheduleMutator(short phaseId) { 248 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase); 249 return (SCHEDULE_MUTATOR << 16) + phaseId; 250 } 251 252 /** 253 * Take the passed phase and return an encoded phase to 254 * run that phase in a mutator context; 255 * 256 * @param phaseId The phase to run on mutators 257 * @return The encoded phase value. 258 */ 259 public static int schedulePlaceholder(short phaseId) { 260 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase); 261 return (SCHEDULE_PLACEHOLDER << 16) + phaseId; 262 } 263 264 /*********************************************************************** 265 * 266 * Phase instance fields/methods. 267 */ 268 269 /** 270 * The unique phase identifier. 271 */ 272 protected final short id; 273 274 /** 275 * The name of the phase. 276 */ 277 protected final String name; 278 279 /** 280 * The Timer that is started and stopped around the execution of this 281 * phase. 282 */ 283 protected final Timer timer; 284 285 /** 286 * Create a new Phase. This involves creating a corresponding Timer 287 * instance, allocating a unique identifier, and registering the 288 * Phase. 289 * 290 * @param name The name for the phase. 291 */ 292 protected Phase(String name) { 293 this(name, new Timer(name, false, true)); 294 } 295 296 /** 297 * Create a new phase. This involves setting the corresponding Timer 298 * instance, allocating a unique identifier, and registering the Phase. 299 * 300 * @param name The name of the phase. 301 * @param timer The timer, or null if this is an untimed phase. 302 */ 303 protected Phase(String name, Timer timer) { 304 this.name = name; 305 this.timer = timer; 306 this.id = nextPhaseId++; 307 phases[this.id] = this; 308 } 309 310 /** 311 * @return The unique identifier for this phase. 312 */ 313 public final short getId() { 314 return this.id; 315 } 316 317 /** 318 * Display a description of this phase, for debugging purposes. 319 */ 320 protected abstract void logPhase(); 321 322 /*********************************************************************** 323 * 324 * Phase stack 325 */ 326 327 /** The maximum stack depth for the phase stack. */ 328 private static final int MAX_PHASE_STACK_DEPTH = MAX_PHASES; 329 330 /** Stores the current sub phase for a complex phase. Each entry corresponds to a phase stack entry */ 331 private static int[] complexPhaseCursor = new int[MAX_PHASE_STACK_DEPTH]; 332 333 /** The phase stack. Stores the current nesting of phases */ 334 private static int[] phaseStack = new int[MAX_PHASE_STACK_DEPTH]; 335 336 /** The current stack pointer */ 337 private static int phaseStackPointer = -1; 338 339 /** 340 * The current even (0 mod 2) scheduled phase. 341 * As we only sync at the end of a phase we need this to ensure that 342 * the primary thread setting the phase does not race with the other 343 * threads reading it. 344 */ 345 private static int evenScheduledPhase; 346 347 /** 348 * The current odd (1 mod 2) scheduled phase. 349 * As we only sync at the end of a phase we need this to ensure that 350 * the primary thread setting the phase does not race with the other 351 * threads reading it. 352 */ 353 private static int oddScheduledPhase; 354 355 /** 356 * Do we need to add a sync point to reset the mutator count. This 357 * is necessary for consecutive mutator phases and unnecessary 358 * otherwise. Again we separate in even and odd to ensure that there 359 * is no race between the primary thread setting and the helper 360 * threads reading. 361 */ 362 private static boolean evenMutatorResetRendezvous; 363 364 /** 365 * Do we need to add a sync point to reset the mutator count. This 366 * is necessary for consecutive mutator phases and unnecessary 367 * otherwise. Again we separate in even and odd to ensure that there 368 * is no race between the primary thread setting and the helper 369 * threads reading. 370 */ 371 private static boolean oddMutatorResetRendezvous; 372 373 /** 374 * The complex phase whose timer should be started after the next 375 * rendezvous. We can not start the timer at the point we determine 376 * the next complex phase as we determine the next phase at the 377 * end of the previous phase before the sync point. 378 */ 379 private static short startComplexTimer; 380 381 /** 382 * The complex phase whose timer should be stopped after the next 383 * rendezvous. We can not start the timer at the point we determine 384 * the next complex phase as we determine the next phase at the 385 * end of the previous phase before the sync point. 386 */ 387 private static short stopComplexTimer; 388 389 /** 390 * Place a phase on the phase stack and begin processing. 391 * 392 * @param scheduledPhase The phase to execute 393 */ 394 public static void beginNewPhaseStack(int scheduledPhase) { 395 int order = ((ParallelCollector)VM.activePlan.collector()).rendezvous(); 396 397 if (order == 0) { 398 pushScheduledPhase(scheduledPhase); 399 } 400 processPhaseStack(false); 401 } 402 403 /** 404 * Continue the execution of a phase stack. Used for incremental 405 * and concurrent collection. 406 */ 407 public static void continuePhaseStack() { 408 processPhaseStack(true); 409 } 410 411 /** 412 * Processes the phase stack. This method is called by multiple threads. 413 * 414 * @param resume whether to resume garbage collection. If set to {@code true}, 415 * GC status will be set to {@link Plan#GC_PROPER} when the first phase 416 * is processed. 417 */ 418 private static void processPhaseStack(boolean resume) { 419 /* Global and Collector instances used in phases */ 420 Plan plan = VM.activePlan.global(); 421 ParallelCollector collector = (ParallelCollector)VM.activePlan.collector(); 422 423 int order = collector.rendezvous(); 424 final boolean primary = order == 0; 425 426 boolean log = Options.verbose.getValue() >= 6; 427 boolean logDetails = Options.verbose.getValue() >= 7; 428 429 if (primary && resume) { 430 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Phase.isPhaseStackEmpty()); 431 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress()); 432 Plan.setGCStatus(Plan.GC_PROPER); 433 } 434 435 /* In order to reduce the need for synchronization, we keep an odd or even 436 * counter for the number of phases processed. As each phase has a single 437 * rendezvous it is only possible to be out by one so the odd or even counter 438 * protects us. */ 439 boolean isEvenPhase = true; 440 441 if (primary) { 442 /* Only allow concurrent collection if we are not collecting due to resource exhaustion */ 443 allowConcurrentPhase = Plan.isInternalTriggeredCollection() && !Plan.isEmergencyCollection(); 444 445 /* First phase will be even, so we say we are odd here so that the next phase set is even*/ 446 setNextPhase(false, getNextPhase(), false); 447 } 448 449 /* Make sure everyone sees the first phase */ 450 collector.rendezvous(); 451 452 /* The main phase execution loop */ 453 int scheduledPhase; 454 while ((scheduledPhase = getCurrentPhase(isEvenPhase)) > 0) { 455 short schedule = getSchedule(scheduledPhase); 456 short phaseId = getPhaseId(scheduledPhase); 457 Phase p = getPhase(phaseId); 458 459 /* Start the timer(s) */ 460 if (primary) { 461 if (resume) { 462 resumeComplexTimers(); 463 } 464 if (p.timer != null) p.timer.start(); 465 if (startComplexTimer > 0) { 466 Phase.getPhase(startComplexTimer).timer.start(); 467 startComplexTimer = 0; 468 } 469 } 470 471 if (log) { 472 Log.write("Execute "); 473 p.logPhase(); 474 } 475 476 /* Execute a single simple scheduled phase */ 477 switch (schedule) { 478 /* Global phase */ 479 case SCHEDULE_GLOBAL: { 480 if (logDetails) Log.writeln(" as Global..."); 481 if (primary) { 482 if (VM.DEBUG) VM.debugging.globalPhase(phaseId,true); 483 plan.collectionPhase(phaseId); 484 if (VM.DEBUG) VM.debugging.globalPhase(phaseId,false); 485 } 486 break; 487 } 488 489 /* Collector phase */ 490 case SCHEDULE_COLLECTOR: { 491 if (logDetails) Log.writeln(" as Collector..."); 492 if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,true); 493 collector.collectionPhase(phaseId, primary); 494 if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,false); 495 break; 496 } 497 498 /* Mutator phase */ 499 case SCHEDULE_MUTATOR: { 500 if (logDetails) Log.writeln(" as Mutator..."); 501 /* Iterate through all mutator contexts */ 502 MutatorContext mutator; 503 while ((mutator = VM.activePlan.getNextMutator()) != null) { 504 if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),true); 505 mutator.collectionPhase(phaseId, primary); 506 if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),false); 507 } 508 break; 509 } 510 511 /* Concurrent phase */ 512 case SCHEDULE_CONCURRENT: { 513 /* We are yielding to a concurrent collection phase */ 514 if (logDetails) Log.writeln(" as Concurrent, yielding..."); 515 if (primary) { 516 concurrentPhaseId = phaseId; 517 /* Concurrent phase, we need to stop gc */ 518 Plan.setGCStatus(Plan.NOT_IN_GC); 519 Plan.controlCollectorContext.requestConcurrentCollection(); 520 } 521 collector.rendezvous(); 522 if (primary) { 523 pauseComplexTimers(); 524 } 525 return; 526 } 527 528 default: { 529 /* getNextPhase has done the wrong thing */ 530 VM.assertions.fail("Invalid schedule in Phase.processPhaseStack"); 531 break; 532 } 533 } 534 535 if (primary) { 536 /* Set the next phase by processing the stack */ 537 int next = getNextPhase(); 538 boolean needsResetRendezvous = (next > 0) && (schedule == SCHEDULE_MUTATOR && getSchedule(next) == SCHEDULE_MUTATOR); 539 setNextPhase(isEvenPhase, next, needsResetRendezvous); 540 } 541 542 /* Sync point after execution of a phase */ 543 collector.rendezvous(); 544 545 /* Mutator phase reset */ 546 if (primary && schedule == SCHEDULE_MUTATOR) { 547 VM.activePlan.resetMutatorIterator(); 548 } 549 550 /* At this point, in the case of consecutive phases with mutator 551 * scheduling, we have to double-synchronize to ensure all 552 * collector threads see the reset mutator counter. */ 553 if (needsMutatorResetRendezvous(isEvenPhase)) { 554 collector.rendezvous(); 555 } 556 557 /* Stop the timer(s) */ 558 if (primary) { 559 if (p.timer != null) p.timer.stop(); 560 if (stopComplexTimer > 0) { 561 Phase.getPhase(stopComplexTimer).timer.stop(); 562 stopComplexTimer = 0; 563 } 564 } 565 566 /* Flip the even / odd phase sense */ 567 isEvenPhase = !isEvenPhase; 568 resume = false; 569 } 570 } 571 572 /** 573 * @param isEvenPhase whether an even or odd phase will be returned 574 * @return the next phase 575 */ 576 private static int getCurrentPhase(boolean isEvenPhase) { 577 return isEvenPhase ? evenScheduledPhase : oddScheduledPhase; 578 } 579 580 /** 581 * @param isEvenPhase whether the phase is even or odd 582 * @return whether we need a mutator reset rendezvous in this phase 583 */ 584 private static boolean needsMutatorResetRendezvous(boolean isEvenPhase) { 585 return isEvenPhase ? evenMutatorResetRendezvous : oddMutatorResetRendezvous; 586 } 587 /** 588 * Sets the next phase. If we are in an even phase the next phase is odd. 589 * 590 * @param isEvenPhase whether the phase is even 591 * @param scheduledPhase the scheduled phase 592 * @param needsResetRendezvous whether it's necessary to rendezvous. This is 593 * only necessary for consecutive mutator phases. 594 */ 595 private static void setNextPhase(boolean isEvenPhase, int scheduledPhase, boolean needsResetRendezvous) { 596 if (isEvenPhase) { 597 oddScheduledPhase = scheduledPhase; 598 evenMutatorResetRendezvous = needsResetRendezvous; 599 } else { 600 evenScheduledPhase = scheduledPhase; 601 oddMutatorResetRendezvous = needsResetRendezvous; 602 } 603 } 604 605 /** 606 * Pull the next scheduled phase off the stack. This may involve 607 * processing several complex phases and skipping placeholders, etc. 608 * 609 * @return The next phase to run, or -1 if no phases are left. 610 */ 611 private static int getNextPhase() { 612 while (phaseStackPointer >= 0) { 613 int scheduledPhase = peekScheduledPhase(); 614 short schedule = getSchedule(scheduledPhase); 615 short phaseId = getPhaseId(scheduledPhase); 616 617 switch(schedule) { 618 case SCHEDULE_PLACEHOLDER: { 619 /* Placeholders are ignored and we continue looking */ 620 popScheduledPhase(); 621 continue; 622 } 623 624 case SCHEDULE_GLOBAL: 625 case SCHEDULE_COLLECTOR: 626 case SCHEDULE_MUTATOR: { 627 /* Simple phases are just popped off the stack and executed */ 628 popScheduledPhase(); 629 return scheduledPhase; 630 } 631 632 case SCHEDULE_CONCURRENT: { 633 /* Concurrent phases are either popped off or we forward to 634 * an associated non-concurrent phase. */ 635 if (!allowConcurrentPhase) { 636 popScheduledPhase(); 637 ConcurrentPhase cp = (ConcurrentPhase)getPhase(phaseId); 638 int alternateScheduledPhase = cp.getAtomicScheduledPhase(); 639 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSchedule(alternateScheduledPhase) != SCHEDULE_CONCURRENT); 640 pushScheduledPhase(alternateScheduledPhase); 641 continue; 642 } 643 if (VM.VERIFY_ASSERTIONS) { 644 /* Concurrent phases can not have a timer */ 645 VM.assertions._assert(getPhase(getPhaseId(scheduledPhase)).timer == null); 646 } 647 return scheduledPhase; 648 } 649 650 case SCHEDULE_COMPLEX: { 651 /* A complex phase may either be a newly pushed complex phase, 652 * or a complex phase we are in the process of executing in 653 * which case we move to the next subphase. */ 654 ComplexPhase p = (ComplexPhase)getPhase(phaseId); 655 int cursor = incrementComplexPhaseCursor(); 656 if (cursor == 0 && p.timer != null) { 657 /* Tell the primary thread to start the timer after the next sync. */ 658 startComplexTimer = phaseId; 659 } 660 if (cursor < p.count()) { 661 /* There are more entries, we push the next one and continue */ 662 pushScheduledPhase(p.get(cursor)); 663 continue; 664 } 665 666 /* We have finished this complex phase */ 667 popScheduledPhase(); 668 if (p.timer != null) { 669 /* Tell the primary thread to stop the timer after the next sync. */ 670 stopComplexTimer = phaseId; 671 } 672 continue; 673 } 674 675 default: { 676 VM.assertions.fail("Invalid phase type encountered"); 677 } 678 } 679 } 680 return -1; 681 } 682 683 /** 684 * Pause all of the timers for the complex phases sitting in the stack. 685 */ 686 private static void pauseComplexTimers() { 687 for (int i = phaseStackPointer; i >= 0; i--) { 688 Phase p = getPhase(getPhaseId(phaseStack[i])); 689 if (p.timer != null) p.timer.stop(); 690 } 691 } 692 693 /** 694 * Resume all of the timers for the complex phases sitting in the stack. 695 */ 696 private static void resumeComplexTimers() { 697 for (int i = phaseStackPointer; i >= 0; i--) { 698 Phase p = getPhase(getPhaseId(phaseStack[i])); 699 if (p.timer != null) p.timer.start(); 700 } 701 } 702 703 /** 704 * Return true if phase stack is empty, false otherwise. 705 * 706 * @return true if phase stack is empty, false otherwise. 707 */ 708 @Inline 709 public static boolean isPhaseStackEmpty() { 710 return phaseStackPointer < 0; 711 } 712 713 /** 714 * Clears the scheduled phase stack. 715 */ 716 @Inline 717 public static void resetPhaseStack() { 718 phaseStackPointer = -1; 719 } 720 721 /** 722 * Push a scheduled phase onto the top of the work stack. 723 * 724 * @param scheduledPhase The scheduled phase. 725 */ 726 @Inline 727 public static void pushScheduledPhase(int scheduledPhase) { 728 phaseStack[++phaseStackPointer] = scheduledPhase; 729 complexPhaseCursor[phaseStackPointer] = 0; 730 } 731 732 /** 733 * Increment the cursor associated with the current phase 734 * stack entry. This is used to remember the current sub phase 735 * when executing a complex phase. 736 * 737 * @return The old value of the cursor. 738 */ 739 @Inline 740 private static int incrementComplexPhaseCursor() { 741 return complexPhaseCursor[phaseStackPointer]++; 742 } 743 744 /** 745 * Pop off the scheduled phase at the top of the work stack. 746 * @return the scheduled phase at the top of the work stack 747 */ 748 @Inline 749 private static int popScheduledPhase() { 750 return phaseStack[phaseStackPointer--]; 751 } 752 753 /** 754 * Peek the scheduled phase at the top of the work stack. 755 * @return the scheduled phase at the top of the work stack 756 */ 757 @Inline 758 private static int peekScheduledPhase() { 759 return phaseStack[phaseStackPointer]; 760 } 761 762 /** The concurrent phase being executed */ 763 private static short concurrentPhaseId; 764 /** Do we want to allow new concurrent workers to become active */ 765 private static boolean allowConcurrentPhase; 766 767 /** 768 * @return the current phase Id. 769 */ 770 public static short getConcurrentPhaseId() { 771 return concurrentPhaseId; 772 } 773 774 /** 775 * Clear the current phase Id. 776 */ 777 public static void clearConcurrentPhase() { 778 concurrentPhaseId = 0; 779 } 780 781 /** 782 * @return {@code true}if there is an active concurrent phase. 783 */ 784 public static boolean concurrentPhaseActive() { 785 return (concurrentPhaseId > 0); 786 } 787 788 /** 789 * Notify that the concurrent phase has completed successfully. This must 790 * only be called by a single thread after it has determined that the 791 * phase has been completed successfully. 792 * 793 * @return {@code true} if more concurrent work needs to be done right now, 794 * {@code false} otherwise 795 */ 796 @Unpreemptible 797 public static boolean notifyConcurrentPhaseComplete() { 798 if (Options.verbose.getValue() >= 2) { 799 Log.write("< Concurrent phase "); 800 Log.write(getName(concurrentPhaseId)); 801 Log.writeln(" complete >"); 802 } 803 /* Concurrent phase is complete*/ 804 concurrentPhaseId = 0; 805 /* Remove it from the stack */ 806 popScheduledPhase(); 807 /* Pop the next phase off the stack */ 808 int nextScheduledPhase = getNextPhase(); 809 810 if (nextScheduledPhase > 0) { 811 short schedule = getSchedule(nextScheduledPhase); 812 813 /* A concurrent phase, lets wake up and do it all again */ 814 if (schedule == SCHEDULE_CONCURRENT) { 815 concurrentPhaseId = getPhaseId(nextScheduledPhase); 816 return true; 817 } 818 819 /* Push phase back on and resume atomic collection */ 820 pushScheduledPhase(nextScheduledPhase); 821 Plan.triggerInternalCollectionRequest(); 822 } 823 return false; 824 } 825 826 /** 827 * Notify that the concurrent phase has not finished, and must be 828 * re-attempted. 829 */ 830 public static void notifyConcurrentPhaseIncomplete() { 831 if (Options.verbose.getValue() >= 2) { 832 Log.write("< Concurrent phase "); 833 Log.write(getName(concurrentPhaseId)); 834 Log.writeln(" incomplete >"); 835 } 836 } 837}