/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.ia32;
import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
import static org.jikesrvm.ia32.RegisterConstants.ESP;
import static org.jikesrvm.ia32.StackframeLayoutConstants.INVISIBLE_METHOD_ID;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_BODY_OFFSET;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_HEADER_SIZE;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP;
import org.jikesrvm.VM;
import org.jikesrvm.architecture.AbstractRegisters;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.scheduler.RVMThread;
import org.vmmagic.pragma.Entrypoint;
import org.vmmagic.pragma.NonMoving;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
/**
* The machine state comprising a thread's execution context, used both for
* thread context switching and for software/hardware exception
* reporting/delivery.
*/
@Uninterruptible
@NonMoving
public final class Registers extends AbstractRegisters {
/** Frame pointer */
@Entrypoint
public Address fp;
@Override
public void clear() {
fp = Address.zero();
super.clear();
}
/**
* @return framepointer for the deepest stackframe
*/
@Override
public Address getInnermostFramePointer() {
return fp;
}
/**
* @return next instruction address for the deepest stackframe
*/
@Override
public Address getInnermostInstructionAddress() {
return ip;
}
/**
* Updates the machine state as if the stackframe were unwound.
*/
@Override
public void unwindStackFrame() {
ip = Magic.getReturnAddress(fp, RVMThread.getCurrentThread());
fp = Magic.getCallerFramePointer(fp);
}
/**
* Sets ip & fp. used to control the stack frame at which a scan of
* the stack during GC will start, for ex., the top java frame for
* a thread that is blocked in native code during GC.
*
* @param newip the new instruction pointer
* @param newfp the new frame pointer
*/
@Override
public void setInnermost(Address newip, Address newfp) {
ip = newip;
fp = newfp;
}
/**
* set ip and fp values to those of the caller. used just prior to entering
* sigwait to set fp & ip so that GC will scan the threads stack
* starting at the frame of the method that called sigwait.
*/
public void setInnermost() {
Address current_fp = Magic.getFramePointer();
ip = Magic.getReturnAddress(current_fp);
fp = Magic.getCallerFramePointer(current_fp);
}
/**
* The following method initializes a thread stack as if
* "startoff" method had been called by an empty baseline-compiled
* "sentinel" frame with one local variable
*
* @param ip The instruction pointer for the "startoff" method
* @param sp The base of the stack
*/
@Override
@Uninterruptible
public void initializeStack(Address ip, Address sp) {
Address fp;
sp = sp.minus(STACKFRAME_HEADER_SIZE); // last word of header
fp = sp.minus(BYTES_IN_ADDRESS).minus(STACKFRAME_BODY_OFFSET);
Magic.setCallerFramePointer(fp, STACKFRAME_SENTINEL_FP);
Magic.setCompiledMethodID(fp, INVISIBLE_METHOD_ID);
sp = sp.minus(BYTES_IN_ADDRESS); // allow for one local
getGPRs().set(ESP.value(), sp.toWord());
this.fp = fp;
this.ip = ip;
}
/**
* A thread's stack has been moved or resized.
* Adjust the ESP register to reflect new position.
*
* @param delta The displacement to be applied
* @param traceAdjustments Log all adjustments to stderr if true
*/
@Uninterruptible
@Override
public void adjustESP(Offset delta, boolean traceAdjustments) {
Word old = getGPRs().get(ESP.value());
getGPRs().set(ESP.value(), old.plus(delta));
if (traceAdjustments) {
VM.sysWrite(" esp =");
VM.sysWrite(getGPRs().get(ESP.value()));
}
}
@Override
public void dump() {
super.dump();
VM.sysWriteln("fp = ",fp);
}
}