/*
* 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.ppc;
import static org.jikesrvm.ppc.RegisterConstants.FRAME_POINTER;
import static org.jikesrvm.ppc.StackframeLayoutConstants.INVISIBLE_METHOD_ID;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_ALIGNMENT;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_FRAME_POINTER_OFFSET;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_HEADER_SIZE;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP;
import org.jikesrvm.VM;
import org.jikesrvm.architecture.AbstractRegisters;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.runtime.Memory;
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.
*/
@Uninterruptible
@NonMoving
public final class Registers extends AbstractRegisters {
// The following are used by exception delivery.
// They are set by either Runtime.athrow or the C hardware exception
// handler and restored by "Magic.restoreHardwareExceptionState".
// They are not used for context switching.
//
/** link register */
@Entrypoint
public Address lr;
/** do exception registers currently contain live values? */
private static final Address invalidIP = Address.max();
public Registers() {
ip = invalidIP;
}
@Override
public void clear() {
lr = Address.zero();
super.clear();
}
@Override
public void dump() {
super.dump();
VM.sysWriteln("lr = ", lr);
}
/** @return framepointer for the deepest stackframe */
@Override
public Address getInnermostFramePointer() {
return getGPRs().get(FRAME_POINTER.value()).toAddress();
}
/** @return next instruction address for the deepest stackframe */
@Override
public Address getInnermostInstructionAddress() {
if (ip.NE(invalidIP)) return ip; // ip set by hardware exception handler or Magic.threadSwitch
return Magic.getNextInstructionAddress(getInnermostFramePointer()); // ip set to -1 because we're unwinding
}
/** Update the machine state to unwind the deepest stackframe. */
@Override
public void unwindStackFrame() {
ip = invalidIP; // if there was a valid value in ip, it ain't valid anymore
getGPRs().set(FRAME_POINTER.value(), Magic.getCallerFramePointer(getInnermostFramePointer()).toWord());
}
/**
* Set 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.
*/
@Override
public void setInnermost(Address newip, Address newfp) {
ip = newip;
getGPRs().set(FRAME_POINTER.value(), newfp.toWord());
}
/**
* 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 fp = Magic.getFramePointer();
ip = Magic.getReturnAddress(fp);
getGPRs().set(FRAME_POINTER.value(), Magic.getCallerFramePointer(fp).toWord());
}
/**
* 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;
// align stack frame
int INITIAL_FRAME_SIZE = STACKFRAME_HEADER_SIZE;
fp = Memory.alignDown(sp.minus(INITIAL_FRAME_SIZE), STACKFRAME_ALIGNMENT);
fp.plus(STACKFRAME_FRAME_POINTER_OFFSET).store(STACKFRAME_SENTINEL_FP);
fp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET).store(ip); // need to fix
fp.plus(STACKFRAME_METHOD_ID_OFFSET).store(INVISIBLE_METHOD_ID);
getGPRs().set(FRAME_POINTER.value(), fp.toWord());
this.ip = ip;
}
@Uninterruptible
@Override
public void adjustESP(Offset delta, boolean traceAdjustments) {
Word old = getGPRs().get(FRAME_POINTER.value());
getGPRs().set(FRAME_POINTER.value(), old.plus(delta));
if (traceAdjustments) {
VM.sysWrite(" esp =");
VM.sysWrite(getGPRs().get(FRAME_POINTER.value()));
}
}
}