package org.jikesrvm.cellspu;
import org.jikesrvm.VM;
import org.jikesrvm.VM_Constants;
import org.jikesrvm.SubordinateArchitecture.VM_ProcessorLocalState;
import org.jikesrvm.runtime.VM_Magic;
import org.jikesrvm.scheduler.VM_Processor;
import org.vmmagic.pragma.Entrypoint;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.LocalAddress;
import org.vmmagic.unboxed.WordArray;
/**
* Methods which are used used by the runtime on the cell spu
*
*/
public class VM_RuntimeMethods implements VM_Constants, VM_ArchConstants {
/** Offset into JTOC of class statics for class being loaded */
private static int classStaticOffset;
/** Offset into class static of method currently being loaded */
private static int methodOffset;
/** Entrypoint of method being loaded and run */
private static VM_CodeArray methodEntry;
/** Number of parameters expected by method */
private static int numParams;
/** parameters - Hack change these into arrays */
private static Object hackParam0, hackParam1, hackParam2, hackParam3;
/**
* This is the initial entry point of the runtime system on the SPU.
* It will sit waiting for a method to run to be supplied by the main runtime.
*
*/
@Entrypoint
public static void runtimeEntry (int phys_id) {
resetMethodDetails();
VM_Magic.writeIntrMailBox(JAVA_VM_STARTED);
VM_Magic.writeIntrMailBox(phys_id);
int cmd = VM_Magic.readIntMailBox();
while (cmd != SET_PROCESSOR_REG) {
VM_Magic.writeIntrMailBox(ERR_UNKNOWN_CMD);
VM_Magic.writeIntrMailBox(cmd);
cmd = VM_Magic.readIntMailBox();
}
Address procAddr = VM_Magic.readRefMailBox();
VM_ProcessorLocalState.setCurrentProcessor((VM_Processor)VM_Magic.addressAsObject(procAddr));
VM_Magic.writeIntrMailBox(ACK);
while (true) {
// Read the next command from the main runtime
cmd = VM_Magic.readIntMailBox();
switch (cmd) {
case LOAD_STATIC_METHOD:
loadStaticMethod();
break;
case LOAD_WORD_PARAM:
loadWordParam();
break;
case LOAD_DOUBLE_PARAM:
loadDoubleParam();
break;
case RUN_METHOD_RETURNING_VOID:
invokeVoidMethod();
break;
case RUN_METHOD_RETURNING_INT:
invokeIntMethod();
break;
case RUN_METHOD_RETURNING_FLOAT:
invokeFloatMethod();
break;
case RUN_METHOD_RETURNING_LONG:
invokeLongMethod();
break;
case RUN_METHOD_RETURNING_DOUBLE:
invokeDoubleMethod();
break;
case RUN_METHOD_RETURNING_REF:
invokeRefMethod();
break;
default:
{
VM_Magic.writeIntrMailBox(ERR_UNKNOWN_CMD);
VM_Magic.writeIntrMailBox(cmd);
break;
}
}
}
}
@Uninterruptible
public static void write(char value) {
int ret_signal;
VM_Magic.writeIntrMailBox(CONSOLE_WRITE_CHAR);
VM_Magic.writeMailBox(value);
// wait for ack
ret_signal = VM_Magic.readIntMailBox();
// TODO - something with this ret signal
}
@Uninterruptible
public static void write(int value, int mode) {
int ret_signal;
VM_Magic.writeIntrMailBox(CONSOLE_WRITE_INT + mode);
VM_Magic.writeMailBox(value);
// wait for ack
ret_signal = VM_Magic.readIntMailBox();
// TODO - something with this ret signal
}
@Uninterruptible
public static void writeDouble(double value, int postDecimalDigits) {
int ret_signal;
VM_Magic.writeIntrMailBox(CONSOLE_WRITE_DOUBLE);
VM_Magic.writeMailBoxUpperWord(value);
VM_Magic.writeMailBoxLowerWord(value);
VM_Magic.writeMailBox(postDecimalDigits);
// wait for ack
ret_signal = VM_Magic.readIntMailBox();
// TODO - something with this ret signal
}
@Uninterruptible
public static void write(long value, int mode) {
int ret_signal;
VM_Magic.writeIntrMailBox(CONSOLE_WRITE_LONG + mode);
VM_Magic.writeMailBoxUpperWord(value);
VM_Magic.writeMailBoxLowerWord(value);
// wait for ack
ret_signal = VM_Magic.readIntMailBox();
// TODO - something with this ret signal
}
private static void loadStaticMethod() {
// read method offset
classStaticOffset = VM_Magic.readIntMailBox();
methodOffset = VM_Magic.readIntMailBox();
// start to pull method into local memory
LocalAddress methodEntryRef = VM_Magic.cacheStaticMethod(methodOffset, classStaticOffset);
methodEntry = (VM_CodeArray) VM_Magic.localAddressAsObject(methodEntryRef);
VM_Magic.writeIntrMailBox(ACK);
}
private static void loadWordParam() {
// read param
// TODO - get rid of this - use arrays to store parameteres
if (numParams == 0) {
hackParam0 = VM_Magic.readRefMailBox();
} else if (numParams == 1) {
hackParam1 = VM_Magic.readRefMailBox();
} else if (numParams == 2) {
hackParam2 = VM_Magic.readRefMailBox();
} else if (numParams == 3) {
hackParam3 = VM_Magic.readRefMailBox();
} else {
VM_Magic.writeMailBox(ERR_TOO_MANY_PARAMS);
VM_Magic.writeIntrMailBox(NACK);
return;
}
numParams++;
VM_Magic.writeIntrMailBox(ACK);
}
private static void loadDoubleParam() {
// read param
// TODO - get rid of this - use arrays to store parameteres
VM_Magic.writeMailBox(ERR_TOO_MANY_PARAMS);
VM_Magic.writeIntrMailBox(NACK);
return;
}
private static boolean checkMethodIsLoaded() {
if (methodOffset == -1) {
VM_Magic.writeMailBox(ERR_METHOD_NOT_PREPARED);
VM_Magic.writeIntrMailBox(NACK);
return false;
}
if (methodEntry == null) {
VM_Magic.writeMailBox(ERR_METHOD_NOT_LOADED);
VM_Magic.writeIntrMailBox(NACK);
return false;
}
if (numParams == -1) {
VM_Magic.writeMailBox(ERR_PARAMS_NOT_LOADED);
VM_Magic.writeIntrMailBox(NACK);
return false;
}
return true;
}
private static void invokeVoidMethod() {
if(!checkMethodIsLoaded()) {
return;
}
VM_Magic.writeIntrMailBox(ACK);
VM_Magic.invokeMethodReturningVoid(methodEntry,
(WordArray)hackParam0,
(double [])hackParam1,
(byte []) hackParam2,
(WordArray)hackParam3);
VM_Magic.sync();
resetMethodDetails();
VM_Magic.writeIntrMailBox(RETURN_VALUE_V);
}
private static void invokeIntMethod() {
if(!checkMethodIsLoaded()) {
return;
}
VM_Magic.writeIntrMailBox(ACK);
int ret = VM_Magic.invokeMethodReturningInt(methodEntry,
(WordArray)hackParam0,
(double [])hackParam1,
(byte []) hackParam2,
(WordArray)hackParam3);
VM_Magic.sync();
resetMethodDetails();
VM_Magic.writeMailBox(ret);
VM_Magic.writeIntrMailBox(RETURN_VALUE_I);
}
private static void invokeFloatMethod() {
if(!checkMethodIsLoaded()) {
return;
}
VM_Magic.writeIntrMailBox(ACK);
float ret = VM_Magic.invokeMethodReturningFloat(methodEntry,
(WordArray)hackParam0,
(double [])hackParam1,
(byte []) hackParam2,
(WordArray)hackParam3);
VM_Magic.sync();
resetMethodDetails();
VM_Magic.writeMailBox(ret);
VM_Magic.writeIntrMailBox(RETURN_VALUE_F);
}
private static void invokeLongMethod() {
if(!checkMethodIsLoaded()) {
return;
}
VM_Magic.writeIntrMailBox(ACK);
long ret = VM_Magic.invokeMethodReturningLong(methodEntry,
(WordArray)hackParam0,
(double [])hackParam1,
(byte []) hackParam2,
(WordArray)hackParam3);
VM_Magic.sync();
resetMethodDetails();
VM_Magic.writeMailBoxUpperWord(ret); // this writes the top word
VM_Magic.writeIntrMailBox(RETURN_VALUE_L_UPPER);
VM_Magic.writeMailBoxLowerWord(ret); // this writes the lower word
VM_Magic.writeIntrMailBox(RETURN_VALUE_L_LOWER);
}
private static void invokeDoubleMethod() {
if(!checkMethodIsLoaded()) {
return;
}
VM_Magic.writeIntrMailBox(ACK);
double ret = VM_Magic.invokeMethodReturningDouble(methodEntry,
(WordArray)hackParam0,
(double [])hackParam1,
(byte []) hackParam2,
(WordArray)hackParam3);
VM_Magic.sync();
resetMethodDetails();
VM_Magic.writeMailBoxUpperWord(ret); // this writes the top word
VM_Magic.writeIntrMailBox(RETURN_VALUE_D_UPPER);
VM_Magic.writeMailBoxLowerWord(ret); // this writes the lower word
VM_Magic.writeIntrMailBox(RETURN_VALUE_D_LOWER);
}
private static void invokeRefMethod() {
if(!checkMethodIsLoaded()) {
return;
}
VM_Magic.writeIntrMailBox(ACK);
Object ret = VM_Magic.invokeMethodReturningObject(methodEntry,
(WordArray)hackParam0,
(double [])hackParam1,
(byte []) hackParam2,
(WordArray)hackParam3);
VM_Magic.sync();
resetMethodDetails();
VM_Magic.writeMailBox(VM_Magic.objectAsAddress(ret));
VM_Magic.writeIntrMailBox(RETURN_VALUE_R);
return;
}
/**
* Reset method details to default to prepare for next method to be invoked
*/
private static void resetMethodDetails() {
methodOffset = -1;
methodEntry = null;
numParams = 0;
hackParam0 = hackParam1 = hackParam2 = hackParam3 = null;
}
}