/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.x86;
import org.jnode.annotation.Internal;
import org.jnode.annotation.MagicPermission;
import org.jnode.vm.VmMagic;
import org.jnode.vm.classmgr.VmIsolatedStatics;
import org.jnode.vm.facade.ObjectVisitor;
import org.jnode.vm.facade.VmHeapManager;
import org.jnode.vm.scheduler.VmThread;
import org.vmmagic.pragma.UninterruptiblePragma;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Word;
/**
* Thread implementation for Intel X86 processor.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
@MagicPermission
public abstract class VmX86Thread extends VmThread {
// State when not running
volatile Word eax;
volatile Word ebx;
volatile Word ecx;
volatile Word edx;
volatile Word esi;
volatile Word edi;
volatile Word eflags;
volatile Address eip;
volatile Address esp;
volatile Address ebp;
private static final int FXSTATE_SIZE = 512 + 16;
public static final int FXF_USED = 0x01; // FX has been used since last thread switch
// Saved state of FPU & XMM
final byte[] fxState;
volatile Address fxStatePtr; // This value is set in assembler code
volatile int fxFlags;
// State upon last system exception
volatile Word exEax;
volatile Word exEbx;
volatile Word exEcx;
volatile Word exEdx;
volatile Word exEsi;
volatile Word exEdi;
volatile Word exEflags;
volatile Address exEip;
volatile Address exEsp;
volatile Address exEbp;
volatile Word exCr2;
// MSR's
private volatile MSR[] readWriteMSRs;
private volatile MSR[] writeOnlyMSRs;
/**
* Initialize this instance
*/
VmX86Thread(VmIsolatedStatics isolatedStatics, int slotSize) {
super(isolatedStatics, slotSize);
fxState = new byte[FXSTATE_SIZE];
}
/**
* Create a new instance. This constructor can only be called during the
* bootstrap phase.
*/
VmX86Thread(VmIsolatedStatics isolatedStatics, byte[] stack, int slotSize) {
super(isolatedStatics, stack, getStackEnd(stack, stack.length, slotSize), stack.length);
fxState = new byte[FXSTATE_SIZE];
}
/**
* @param javaThread
*/
public VmX86Thread(VmIsolatedStatics isolatedStatics, Thread javaThread) {
super(isolatedStatics, javaThread);
fxState = new byte[FXSTATE_SIZE];
}
/**
* Gets the most current stackframe of this thread.
*
* @return Stackframe
*/
@Internal
public final Address getStackFrame() {
return ebp;
}
/**
* Gets the most current instruction pointer of this thread.
* This method is only valid when this thread is not running.
*
* @return IP
*/
protected Address getInstructionPointer() {
return eip;
}
/**
* Gets the stackframe of the last system exception of this thread.
*/
protected Address getExceptionStackFrame() {
return exEbp;
}
/**
* Gets the instruction pointer of the last system exception of this thread.
*/
protected Address getExceptionInstructionPointer() {
return exEip;
}
/**
* Calculate the end of the stack.
*
* @param stack
* @param stackSize
* @return End address of the stack
*/
protected Address getStackEnd(Object stack, int stackSize) {
return ObjectReference.fromObject(stack).toAddress().add(STACK_OVERFLOW_LIMIT_SLOTS * getReferenceSize());
}
/**
* Calculate the end of the stack.
*
* @param stack
* @param stackSize
* @return End address of the stack
*/
private static Address getStackEnd(byte[] stack, int stackSize, int slotSize) {
return VmMagic.getArrayData(stack).add(STACK_OVERFLOW_LIMIT_SLOTS * slotSize);
}
/**
* Gets the size of an object reference (pointer).
*/
protected abstract int getReferenceSize();
/**
* Visit all objects on the stack and register state of this thread.
*
* @param visitor
* @param heapManager
*/
public boolean accept(ObjectVisitor visitor, VmHeapManager heapManager) {
// For now do it stupid, but safe, just scan the whole stack.
final int stackSize = getStackSize();
final Object stack = getStack();
if (stack != null) {
final Address stackBottom = ObjectReference.fromObject(stack).toAddress();
final Address stackTop = stackBottom.add(stackSize);
final Address stackEnd;
if (this == currentThread()) {
stackEnd = stackBottom;
} else {
stackEnd = esp;
}
Address ptr = stackTop;
final int slotSize = getReferenceSize();
while (ptr.GE(stackEnd)) {
final Address child = ptr.loadAddress();
if (child != null) {
if (heapManager.isObject(child)) {
if (!visitor.visit(child)) {
return false;
}
}
}
ptr = ptr.sub(slotSize);
}
}
// Scan registers
Address addr = eax.toAddress();
if (heapManager.isObject(addr)) {
if (!visitor.visit(addr)) {
return false;
}
}
addr = ebx.toAddress();
if (heapManager.isObject(addr)) {
if (!visitor.visit(addr)) {
return false;
}
}
addr = ecx.toAddress();
if (heapManager.isObject(addr)) {
if (!visitor.visit(addr)) {
return false;
}
}
addr = edx.toAddress();
if (heapManager.isObject(addr)) {
if (!visitor.visit(addr)) {
return false;
}
}
addr = esi.toAddress();
if (heapManager.isObject(addr)) {
if (!visitor.visit(addr)) {
return false;
}
}
addr = edi.toAddress();
if (heapManager.isObject(addr)) {
if (!visitor.visit(addr)) {
return false;
}
}
return true;
}
/**
* Sets the MSR arrays.
*
* @param readWriteMSRs
* @param writeOnlyMSRs
* @throws UninterruptiblePragma
*/
public final void setMSRs(MSR[] readWriteMSRs, MSR[] writeOnlyMSRs)
throws UninterruptiblePragma {
this.readWriteMSRs = readWriteMSRs;
this.writeOnlyMSRs = writeOnlyMSRs;
}
/**
* @return Returns the readWriteMSRs.
*/
public final MSR[] getReadWriteMSRs() {
return readWriteMSRs;
}
/**
* @return Returns the writeOnlyMSRs.
*/
public final MSR[] getWriteOnlyMSRs() {
return writeOnlyMSRs;
}
/**
* Gets the end address of the stack of this thread.
*
* @return the stack end address
*/
final Address getStackEnd() {
return stackEnd;
}
//todo protect or hide this method in the future
/**
* Gets the stack pointer of this thread.
* Valid only when the thread is not running.
*
* @return the stack pointer
*/
public final Address getStackPointer() {
return esp;
}
}