/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.mm.mminterface;

import org.jikesrvm.ArchitectureSpecific;
import org.jikesrvm.ArchitectureSpecific.BaselineGCMapIterator;
import org.jikesrvm.ArchitectureSpecific.JNIGCMapIterator;
import org.jikesrvm.ArchitectureSpecificOpt.OptGCMapIterator;
import org.jikesrvm.VM;
import org.jikesrvm.SizeConstants;
import org.jikesrvm.compilers.common.CompiledMethod;
import org.jikesrvm.compilers.common.HardwareTrapGCMapIterator;
import org.jikesrvm.scheduler.RVMThread;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.WordArray;

/**
 * Maintains a collection of compiler specific GCMapIterators that are used
 * by collection threads when scanning thread stacks to locate object references
 * in those stacks. Each collector thread has its own GCMapIteratorGroup.
 *
 * The group contains a GCMapIterator for each type of stack frame that
 * may be found while scanning a stack during garbage collection, including
 * frames for baseline compiled methods, OPT compiled methods, and frames
 * for transitions from Java into JNI native code. These iterators are
 * repsonsible for reporting the location of references in the stack or
 * register save areas.
 *
 * @see GCMapIterator
 * @see CompiledMethod
 * @see CollectorThread
 */
public final class GCMapIteratorGroup implements SizeConstants {

  /** current location (memory address) of each gpr register */
  private final WordArray registerLocations;

  /** iterator for baseline compiled frames */
  private final GCMapIterator baselineIterator;

  /** iterator for opt compiled frames */
  private final GCMapIterator optIterator;

  /** iterator for HardwareTrap stackframes */
  private final GCMapIterator hardwareTrapIterator;

  /** iterator for JNI Java -> C  stackframes */
  private final GCMapIterator jniIterator;

  public GCMapIteratorGroup() {
    registerLocations = WordArray.create(ArchitectureSpecific.ArchConstants.NUM_GPRS);

    baselineIterator = new BaselineGCMapIterator(registerLocations);
    if (VM.BuildForOptCompiler) {
      optIterator = new OptGCMapIterator(registerLocations);
    } else {
      optIterator = null;
    }
    jniIterator = new JNIGCMapIterator(registerLocations);
    hardwareTrapIterator = new HardwareTrapGCMapIterator(registerLocations);
  }

  /**
   * Prepare to scan a thread's stack for object references.
   * Called by collector threads when beginning to scan a threads stack.
   * Calls newStackWalk for each of the contained GCMapIterators.
   * <p>
   * Assumption:  the thread is currently suspended, ie. its saved gprs[]
   * contain the thread's full register state.
   * <p>
   * Side effect: registerLocations[] initialized with pointers to the
   * thread's saved gprs[] (in thread.contextRegisters.gprs)
   * <p>
   * @param thread  Thread whose registers and stack are to be scanned
   */
  @Uninterruptible
  public void newStackWalk(RVMThread thread, Address registerLocation) {
    for (int i = 0; i < ArchitectureSpecific.ArchConstants.NUM_GPRS; ++i) {
      registerLocations.set(i, registerLocation.toWord());
      registerLocation = registerLocation.plus(BYTES_IN_ADDRESS);
    }
    baselineIterator.newStackWalk(thread);
    if (VM.BuildForOptCompiler) {
      optIterator.newStackWalk(thread);
    }
    hardwareTrapIterator.newStackWalk(thread);
    jniIterator.newStackWalk(thread);
  }

  /**
   * Select iterator for scanning for object references in a stackframe.
   * Called by collector threads while scanning a threads stack.
   *
   * @param compiledMethod  CompiledMethod for the method executing
   *                        in the stack frame
   *
   * @return GCMapIterator to use
   */
  @Uninterruptible
  public GCMapIterator selectIterator(CompiledMethod compiledMethod) {
    switch (compiledMethod.getCompilerType()) {
      case CompiledMethod.TRAP:
        return hardwareTrapIterator;
      case CompiledMethod.BASELINE:
        return baselineIterator;
      case CompiledMethod.OPT:
        return optIterator;
      case CompiledMethod.JNI:
        return jniIterator;
    }
    if (VM.VerifyAssertions) {
      VM._assert(false, "GCMapIteratorGroup.selectIterator: Unknown type of compiled method");
    }
    return null;
  }

  /**
   * get the GCMapIterator used for scanning JNI native stack frames.
   *
   * @return jniIterator
   */
  @Uninterruptible
  public GCMapIterator getJniIterator() {
    if (VM.VerifyAssertions) VM._assert(jniIterator != null);
    return jniIterator;
  }
}
