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.jikesrvm.ia32;
014
015import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
016import static org.jikesrvm.ia32.RegisterConstants.ESP;
017import static org.jikesrvm.ia32.StackframeLayoutConstants.INVISIBLE_METHOD_ID;
018import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_BODY_OFFSET;
019import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_HEADER_SIZE;
020import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP;
021
022import org.jikesrvm.VM;
023import org.jikesrvm.architecture.AbstractRegisters;
024import org.jikesrvm.runtime.Magic;
025import org.jikesrvm.scheduler.RVMThread;
026import org.vmmagic.pragma.Entrypoint;
027import org.vmmagic.pragma.NonMoving;
028import org.vmmagic.pragma.Uninterruptible;
029import org.vmmagic.unboxed.Address;
030import org.vmmagic.unboxed.Offset;
031import org.vmmagic.unboxed.Word;
032
033/**
034 * The machine state comprising a thread's execution context, used both for
035 * thread context switching and for software/hardware exception
036 * reporting/delivery.
037 */
038@Uninterruptible
039@NonMoving
040public final class Registers extends AbstractRegisters {
041  /** Frame pointer */
042  @Entrypoint
043  public Address fp;
044
045  @Override
046  public void clear() {
047    fp = Address.zero();
048    super.clear();
049  }
050
051  /**
052   * @return framepointer for the deepest stackframe
053   */
054  @Override
055  public Address getInnermostFramePointer() {
056    return fp;
057  }
058
059  /**
060   * @return next instruction address for the deepest stackframe
061   */
062  @Override
063  public Address getInnermostInstructionAddress() {
064    return ip;
065  }
066
067  /**
068   * Updates the machine state as if the stackframe were unwound.
069   */
070  @Override
071  public void unwindStackFrame() {
072    ip = Magic.getReturnAddress(fp, RVMThread.getCurrentThread());
073    fp = Magic.getCallerFramePointer(fp);
074  }
075
076  /**
077   * Sets ip & fp. used to control the stack frame at which a scan of
078   * the stack during GC will start, for ex., the top java frame for
079   * a thread that is blocked in native code during GC.
080   *
081   * @param newip the new instruction pointer
082   * @param newfp the new frame pointer
083   */
084  @Override
085  public void setInnermost(Address newip, Address newfp) {
086    ip = newip;
087    fp = newfp;
088  }
089
090  /**
091   * set ip and fp values to those of the caller. used just prior to entering
092   * sigwait to set fp & ip so that GC will scan the threads stack
093   * starting at the frame of the method that called sigwait.
094   */
095  public void setInnermost() {
096    Address current_fp = Magic.getFramePointer();
097    ip = Magic.getReturnAddress(current_fp);
098    fp = Magic.getCallerFramePointer(current_fp);
099  }
100
101  /**
102   * The following method initializes a thread stack as if
103   * "startoff" method had been called by an empty baseline-compiled
104   *  "sentinel" frame with one local variable
105   *
106   * @param ip The instruction pointer for the "startoff" method
107   * @param sp The base of the stack
108   */
109  @Override
110  @Uninterruptible
111  public void initializeStack(Address ip, Address sp) {
112    Address fp;
113    sp = sp.minus(STACKFRAME_HEADER_SIZE);                   // last word of header
114    fp = sp.minus(BYTES_IN_ADDRESS).minus(STACKFRAME_BODY_OFFSET);
115    Magic.setCallerFramePointer(fp, STACKFRAME_SENTINEL_FP);
116    Magic.setCompiledMethodID(fp, INVISIBLE_METHOD_ID);
117
118    sp = sp.minus(BYTES_IN_ADDRESS);                                 // allow for one local
119    getGPRs().set(ESP.value(), sp.toWord());
120    this.fp = fp;
121    this.ip = ip;
122  }
123
124  /**
125   * A thread's stack has been moved or resized.
126   * Adjust the ESP register to reflect new position.
127   *
128   * @param delta The displacement to be applied
129   * @param traceAdjustments Log all adjustments to stderr if true
130   */
131  @Uninterruptible
132  @Override
133  public void adjustESP(Offset delta, boolean traceAdjustments) {
134    Word old = getGPRs().get(ESP.value());
135    getGPRs().set(ESP.value(), old.plus(delta));
136    if (traceAdjustments) {
137      VM.sysWrite(" esp =");
138      VM.sysWrite(getGPRs().get(ESP.value()));
139    }
140  }
141
142  @Override
143  public void dump() {
144    super.dump();
145    VM.sysWriteln("fp = ",fp);
146  }
147}
148