VM.sysWaitForVirtualProcessorInitialization();
  static void boot (VM_Thread mainThread) {    if (VM.VerifyAssertions) VM.assert(1 <= numProcessors && numProcessors <= MAX_PROCESSORS);    if (VM.TraceThreads)      trace("VM_Scheduler.boot","numProcessors =", numProcessors);    // Create a VM_Processor object for each virtual cpu that we'll be running.    // Note that the VM_Processor object for the primordial processor    // (the virtual cpu in whose context we are currently running)    // was already created in the boot image by init(), above.    //    VM_Processor primordialProcessor = processors[PRIMORDIAL_PROCESSOR_ID];    if (VM.BuildForDedicatedNativeProcessors) {      processors = new VM_Processor[1 + numProcessors];    } else {      processors = new VM_Processor[1 + numProcessors + 1];    }    processors[PRIMORDIAL_PROCESSOR_ID] = primordialProcessor;    for (int i = PRIMORDIAL_PROCESSOR_ID; ++i <= numProcessors; )      processors[i] = new VM_Processor(i);    if (!VM.BuildForDedicatedNativeProcessors) {      // setting of vpStatusAddress during JDK building of bootimage is not valid      // so reset here...maybe change everything to just use index      primordialProcessor.vpStatusAddress = VM_Magic.objectAsAddress(VM_Processor.vpStatus)+	(primordialProcessor.vpStatusIndex<<2);      // Create NativeDaemonProcessor as N+1st processor in the processors array.      // It is NOT included in "numProcessors" which is the index of the last RVM processor.      //      nativeDPndx = numProcessors + 1;		// the last entry in processors[]                                                if (!VM.BuildForSingleVirtualProcessor && BuildWithNativeDaemon) {	processors[nativeDPndx] = new VM_Processor(numProcessors + 1, VM_Processor.NATIVEDAEMON);	if (VM.TraceThreads)	  trace("VM_Scheduler.boot","created nativeDaemonProcessor with id",nativeDPndx);      } else {	processors[nativeDPndx] = null;	if (VM.TraceThreads)	  trace("VM_Scheduler.boot","NativeDaemonProcessor not created");      }    }    // Create work queues.    //    wakeupQueue     = new VM_ProxyWakeupQueue(VM_EventLogger.WAKEUP_QUEUE);    wakeupMutex     = new VM_ProcessorLock();    debuggerQueue   = new VM_ThreadQueue(VM_EventLogger.DEBUGGER_QUEUE);    debuggerMutex   = new VM_ProcessorLock();    attachThreadQueue = new VM_ThreadQueue(VM_EventLogger.ATTACHTHREAD_QUEUE);    attachThreadMutex = new VM_ProcessorLock();    // RCGC addition    gcWaitQueue     = new VM_ThreadQueue(VM_EventLogger.GC_WAIT_QUEUE);    gcWaitMutex     = new VM_ProcessorLock();    // ~RC addition     collectorQueue  = new VM_ThreadQueue(VM_EventLogger.COLLECTOR_QUEUE);    collectorMutex  = new VM_ProcessorLock();    finalizerQueue  = new VM_ThreadQueue(VM_EventLogger.FINALIZER_QUEUE);    finalizerMutex  = new VM_ProcessorLock();    nativeProcessorQueue  = new VM_ProcessorQueue(VM_EventLogger.DEAD_VP_QUEUE);    nativeProcessorMutex  = new VM_ProcessorLock();          deadQueue       = new VM_DeadThreadQueue(VM_EventLogger.DEAD_QUEUE);    deadVPQueue     = new VM_ProcessorQueue(VM_EventLogger.DEAD_VP_QUEUE);    availableProcessorQueue     = new VM_ProcessorQueue(VM_EventLogger.DEAD_VP_QUEUE);          // Create one collector thread and one idle thread per processor.    //    VM_CollectorThread.boot(numProcessors);    for (int i = 0; i < numProcessors; ++i) {      VM_Thread t;      t = VM_CollectorThread.createActiveCollectorThread(collectorThreadStacks[i], processors[1+i]);      t.isAlive = true;      processors[1+i].readyQueue.enqueue(t);      t = new VM_IdleThread(processors[1+i]);      t.isAlive = true;      processors[1+i].idleQueue.enqueue(t);    }    VM_Thread t;    if (!VM.BuildForDedicatedNativeProcessors && !VM.BuildForSingleVirtualProcessor && (processors[nativeDPndx] != null)) {      // Create one collector thread and one idle thread for the NATIVEDAEMON processor      t = VM_CollectorThread.createActiveCollectorThread(collectorThreadStacks[numProcessors], processors[nativeDPndx]);      t.isAlive = true;      processors[nativeDPndx].readyQueue.enqueue(t);      t = new VM_IdleThread(processors[nativeDPndx]);      t.isAlive = true;      processors[nativeDPndx].idleQueue.enqueue(t);      // create the NativeDaemonThread that runs on the NativeDaemonProcessor      t = new VM_NativeDaemonThread(processors[nativeDPndx]);      t.isAlive = true;      processors[nativeDPndx].readyQueue.enqueue(t);    }    // Create one debugger thread.    //    t = new DebuggerThread();    t.isAlive = true;    debuggerQueue.enqueue(t);             // JNI support    attachThreadRequested = 0;    terminated = false;             // Schedule "main" thread for execution.    //    VM_Processor.getCurrentProcessor().scheduleThread(mainThread);    // Create the FinalizerThread    //    FinalizerThread tt = new FinalizerThread();    tt.makeDaemon(true);    VM_Processor.getCurrentProcessor().scheduleThread(tt);    // Create virtual cpu's.    //    processors[PRIMORDIAL_PROCESSOR_ID].isInitialized = true; // the one we're running on    if (cpuAffinity != NO_CPU_AFFINITY)      VM.sysVirtualProcessorBind(cpuAffinity + PRIMORDIAL_PROCESSOR_ID - 1); // bind it to a physical cpu    for (int i = PRIMORDIAL_PROCESSOR_ID; ++i <= numProcessors; ) {      // create VM_Thread for virtual cpu to execute      //      VM_Thread target = new VM_StartupThread(startupThreadStacks[i-1]);      // create virtual cpu and wait for execution to enter target's code/stack.      // this is done with gc disabled to ensure that garbage collector doesn't move      // code or stack before the C startoff function has a chance      // to transfer control into vm image.      //      if (VM.TraceThreads)	trace("VM_Scheduler.boot", "starting processor id", i);      VM.disableGC();      processors[i].activeThread = target;      //-#if RVM_FOR_POWERPC      VM.sysVirtualProcessorCreate(VM_Magic.getTocPointer(),				   VM_Magic.objectAsAddress(processors[i]),				   target.contextRegisters.gprs[THREAD_ID_REGISTER],				   target.contextRegisters.gprs[FRAME_POINTER]);      //-#endif      //-#if RVM_FOR_IA32      VM.sysVirtualProcessorCreate(VM_Magic.getTocPointer(),				   VM_Magic.objectAsAddress(processors[i]),				   target.contextRegisters.ip,				   target.contextRegisters.fp);      //-#endif      int loop_count = 1;      if (VM.TraceThreads)	trace("VM_Scheduler.boot", "starting to wait for processor id", i);      while (!processors[i].isInitialized) {	++loop_count;	if ( VM.TraceThreads && loop_count%100 == 0 )	  trace("VM_Scheduler.boot","waiting for processor - loop_count =",loop_count);	if ( loop_count%10000 == 0 ) 	  VM.sysFail("VM_Scheduler.boot: hanging after sysVirtualProcessorCreate()");	VM.sysVirtualProcessorYield();      }      VM.enableGC();      if (VM.TraceThreads)	trace("VM_Scheduler.boot", "started processor id", i);    }    if (!VM.BuildForDedicatedNativeProcessors &&!VM.BuildForSingleVirtualProcessor && (processors[nativeDPndx] != null)) {      VM_Thread target = new VM_StartupThread(startupThreadStacks[numProcessors]);      VM.disableGC();      processors[nativeDPndx].activeThread = target;      if (VM.TraceThreads)	trace("VM_Scheduler.boot", "starting native daemon processor id", nativeDPndx);      //-#if RVM_FOR_POWERPC	VM.sysVirtualProcessorCreate(VM_Magic.getTocPointer(),				     VM_Magic.objectAsAddress(processors[nativeDPndx]),				     target.contextRegisters.gprs[THREAD_ID_REGISTER],				     target.contextRegisters.gprs[FRAME_POINTER]);      //-#endif      //-#if RVM_FOR_IA32	VM.sysVirtualProcessorCreate(VM_Magic.getTocPointer(),				     VM_Magic.objectAsAddress(processors[nativeDPndx]),				     0,				     target.contextRegisters.fp);      //-#endif      while (!processors[nativeDPndx].isInitialized)	VM.sysVirtualProcessorYield();      VM.enableGC();      if (VM.TraceThreads)	trace("VM_Scheduler.boot", "started native daemon processor id", nativeDPndx);    }    // Allow virtual cpus to commence feeding off the work queues.    //    allProcessorsInitialized = true;    //    for (int i = PRIMORDIAL_PROCESSOR_ID; i <= numProcessors; ++i)    //      processors[i].enableThreadSwitching();    VM_Processor.getCurrentProcessor().enableThreadSwitching();    // Start interrupt driven timeslicer to improve threading fairness and responsiveness.    //    if (!VM.BuildForDeterministicThreadSwitching)      VM.sysVirtualProcessorEnableTimeSlicing();    // Start event logger.    //    if (VM.BuildForEventLogging)      VM_EventLogger.boot();    // End of boot thread. Relinquish control to next job on work queue.    //    if (VM.TraceThreads)      trace("VM_Scheduler.boot", "completed - terminating");    VM_Thread.terminate();    if (VM.VerifyAssertions) VM.assert(VM.NOT_REACHED);  }     //  // Debugging aids.  //  /**   * Override standard assertion checker.   * @deprecated Should use VM.assert()   */  static void assert(boolean b) {    VM.assert(b);  }