/**
   * This method is the entry point to the controller, it is called when the controllerThread is
   * created.
   */
  public void run() {
    // save this object so others can access it, if needed
    Controller.controllerThread = this;

    // Bring up the logging system
    AOSLogging.logger.boot();
    if (Controller.options.ENABLE_ADVICE_GENERATION) {
      AOSGenerator.boot();
    }

    // Create measurement entities that are NOT related to
    // adaptive recompilation
    createProfilers();

    if (!Controller.options.ENABLE_RECOMPILATION) {
      // We're running an AOS bootimage with a non-adaptive primary strategy.
      // We already set up any requested profiling infrastructure, so nothing
      // left to do but exit.
      controllerInitDone();
      VM.sysWriteln("AOS: In non-adaptive mode; controller thread exiting.");
      return; // controller thread exits.
    }

    if ((Controller.options.ENABLE_REPLAY_COMPILE) || (Controller.options.ENABLE_PRECOMPILE)) {
      // if we want to do precompile, we need to initial optimization plans
      // just allow the advice to be the max opt level 2
      Controller.options.DERIVED_MAX_OPT_LEVEL = 2;
      if (Controller.options.sampling()) {
        // Create our set of standard optimization plans.
        Controller.recompilationStrategy.init();
      } else if (Controller.options.counters()) {
        InvocationCounts.init();
      }
      Controller.osrOrganizer = new OSROrganizerThread();
      Controller.osrOrganizer.start();
      createCompilationThread();
      // We're running an AOS bootimage with a non-adaptive primary strategy.
      // We already set up any requested profiling infrastructure, so nothing
      // left to do but exit.
      controllerInitDone();
      // to have a fair comparison, we need to create the data structures
      // of organizers
      createOrganizerThreads();
      VM.sysWriteln("AOS: In replay mode; controller thread only runs for OSR inlining.");
      while (true) {
        if (Controller.options.EARLY_EXIT
            && Controller.options.EARLY_EXIT_TIME < Controller.controllerClock) {
          Controller.stop();
        }
        Object event = Controller.controllerInputQueue.deleteMin();
        ((OnStackReplacementEvent) event).process();
      }
    }

    // Initialize the CompilerDNA class
    // This computes some internal options, must be done early in boot process
    CompilerDNA.init();

    // Create the organizerThreads and schedule them
    createOrganizerThreads();

    // Create the compilationThread and schedule it
    createCompilationThread();

    if (Controller.options.sampling()) {
      // Create our set of standard optimization plans.
      Controller.recompilationStrategy.init();
    } else if (Controller.options.counters()) {
      InvocationCounts.init();
    }

    controllerInitDone();

    // Enter main controller loop.
    // Pull an event to process off of
    // Controller.controllerInputQueue and handle it.
    // If no events are on the queue, then the deleteMin call will
    // block until an event is available.
    // Repeat forever.
    while (true) {
      if (Controller.options.EARLY_EXIT
          && Controller.options.EARLY_EXIT_TIME < Controller.controllerClock) {
        Controller.stop();
      }
      Object event = Controller.controllerInputQueue.deleteMin();
      ((ControllerInputEvent) event).process();
    }
  }