/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2006, Rasmus Ulslev Pedersen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package wcet.gc;
//import com.jopdesign.sys.Const;
// History:
// 2005-12-15: ms idea: Copy and paste from JVMHelp
// 2005-12-15: rup: Only inspect local vars + operands
// 2006-01-15: Operand walker
// 2006-01-27: Reduced word count by indexed version
//TODO: top frame inspection, the initialization issue from Sitescape
/**
* It inspects the stack of a given thread and returns a reference to an array of stack
* with the references for a given PC value marked with 1.
* The <code>swk</code> method is called from the GC's getRoots method.
* @author rup, ms
*/
public class GCStkWalk {
static final int MAXSTACK = 128;
static int stack[];
// gcpack, see also MethodInfo.dumpMethodGcis
static final int UNICNTLEN = 10; // count of unique patterns
static final int INSTRLEN = 10; //1024 instructions
static final int MAXSTACKLEN = 5; // max 31 operands
static final int MAXLOCALSLEN = 5; // max 31 args+locals
static final int STACKMARKLEN = 1; // 1 if stack references
static final int LOCALMARKLEN = 1; // 1 if local references
//indexes of the root items for the stack that is scanned using swk(int)
private final static int[] roots = new int[MAXSTACK];
// used by swk method and the other utility methods
static int sp, cp, fp, mp, vp, pc, addr, loc, args, mstk, mloc;
static int gcpack, val, active, num, infoaddr, instr;
static int localmarkword, stackmarkword, indexbits, unicnt, length;
//Walk one stack and then you should access refPos
//All non-active stacks should have
// the waitForNextPeriod stack frame on top of its
// stack. It should have no operands and thus we know
// the frame pointer and can decuct vp of the previous
// threads.
//If it is the active thread that invokes this method then
// the swk(int) method is the top frame, which we do not inspect (should we?)
/**
* It walks the stack for a given thread. Its behavior depends if it is walking the
* the active stack or not so that is flagged in the arguments.
* @param num index of the thread to be "walked"
* @param active if the thread is the active one
* @param info if true then a lot of debug info is printed (which can cause
* the GC to miss the deadlines...)
* @return the root set marked with 1 for references, 0 for primitives and -1 for other
* stack things from the frames.
*/
public static int[] swk(int num, boolean active, boolean info) {
// int ts=Timer.us();
// int ts1=0;
// if(info){
// System.out.print("GCStkWalk.swk called(num=");
// System.out.print(num);
// System.out.print(",");
// if(active)
// System.out.print("active=true");
// else
// System.out.print("active=false");
// if(info)
// System.out.println("info=true)");
// else
// System.out.println("info=false)");
// }
// mark local refs and operand refs with 1, primitives with 0,
// and the rest with -1. This array has plenty room for packing
// more information if needed. For example using 1 for local refs and
// 2 for operand refs.
//enable
// for(int i=0;i<MAXSTACK;i++){
// roots[i]=-1;
// }
// if(active){
sp = Native.getSP();
// } else //walk one of the saved stacks
// {
// sp = RtThreadImpl.getSP(num);
// stack = RtThreadImpl.getStack(num);
// }
fp = sp - 4; // last sp points to the end of the frame
//stop befor 'first' method, loop = 255-4-128-5/5 =
while (fp > 128 + 5) { // @WCA loop=5
// saved vars of curent frame that points to
// previous frame. See Fig. 6.2 in ms thesis
//enable
// if(active){
mp = Native.rdIntMem(fp + 4);
cp = Native.rdIntMem(fp + 3);
vp = Native.rdIntMem(fp + 2);
pc = Native.rdIntMem(fp + 1);
sp = Native.rdIntMem(fp);
// } else
// {
// mp = stack[fp + 4 - 128];
// cp = stack[fp + 3 - 128];//Native.rdIntMem(fp + 3);
// vp = stack[fp + 2 - 128];
// pc = stack[fp + 1 - 128];
// sp = stack[fp - 128];
// }
val = Native.rdMem(mp);
addr = val >>> 10; // address of callee
//TODO: Include some pointer in the method stuct.
// Perhaps there is room for the mgcisKey index in the method struct.
// Methodinfo:464
val = Native.rdMem(mp + 1); // cp, locals, args
args = val & 0x1f;
loc = (val >>> 5) & 0x1f;
gcpack = Native.rdMem(addr-1);
mloc = (gcpack>>>(STACKMARKLEN+LOCALMARKLEN))&0x1F;//MAXLOCALSLEN. See gcMaxLocals();
mstk = gcpack&0x01;//STACKMARKLEN gcMaxStack();
unicnt = (gcpack>>>(INSTRLEN+MAXSTACKLEN+MAXLOCALSLEN+STACKMARKLEN+LOCALMARKLEN))&0x03FF; //UNICNTLEN. See gcUniCnt();
instr = (gcpack>>>(MAXSTACKLEN+MAXLOCALSLEN+STACKMARKLEN+LOCALMARKLEN))&0x03FF;//INSTRLEN gcInstr();
// length = gcLength(); // also sets indexbits
fp = vp + args + loc; // the fp can be calc. with vp and count of args + locals
//Just check to see if JOP args count equals the gcpack info
// if((args+loc) != mloc){
// System.out.println("Method "+addr+":"+(args+loc)+"!="+gcMaxLocals());
// System.exit(-1);
// }
length = gcLength();
infoaddr = addr - 1 - length; // now point to first gc info word
// it makes mgci and ogci words for the the PC
setMarkWords();
//Now do that root marking
for(int i=0;i<mloc;i++){ //@WCA loop=32
// don't overwrite the ref belonging to the frame on top of this
if(roots[vp+i-128]==-1){
roots[vp+i-128]=gcLocalMarkBit(i);
}
}
for(int i=0;i<mstk;i++){ //@WCA loop=32
// don't overwrite the ref belonging to the frame on top of this
if(roots[fp+5+i-128]==-1){
roots[fp+5+i-128]=gcStackMarkBit(i);
}
}
// debugging
// if(info){
// wrFrame(num);
// }
} // while loop
// debugging
// if(info){
// wrroots(num);
// }
return roots;
}
// This is a good method for debugging. You start by finding
// the matching method (mpi) id in the .jop file.
/* static void wrFrame(int num){
wr("---Frame info-Thread-no ");
wrSmall(num);
wr("--\n");
wr("gcpack:");
bitStr(gcpack);
wr('\n');
wr("maxStack:");
wrSmall(gcMaxStack());
wr(" maxLocals:");
wrSmall(gcMaxLocals());
wr(" args:");
wrSmall(args);
wr(" loc:");
wrSmall(loc);
wr('\n');
wr("sp:");
wrSmall(sp);
wr(" fp:");
wrSmall(fp);
wr(" mp:");
wrSmall(mp);
wr(" vp:");
wrSmall(vp);
wr(" pc:");
wrSmall(pc);
wr('\n');
wr("instrs:");
wrSmall(gcInstr());
wr(" indexbits:");
wrSmall(indexbits);
wr(" length:");
wrSmall(gcLength());
wr('\n');
wr("uc:");
wrSmall(gcUniCnt());
wr(" addr:");
wrSmall(addr);
wr(" infoaddr:");
wrSmall(infoaddr);
wr('\n');
wr("localmark:");
wrDigit(gcLocalMark());
wr(" stackmark:");
wrDigit(gcStackMark());
wr('\n');
wr("ogis[pc=");
wrSmall(pc);
wr("]:");
int mask = 0x01;
for(int i = 31;i>=0;i--){ // @WCA loop=32
if((i+1)%8==0 && i<31){
wr('_');
}
if(i<gcMaxStack()){
wrDigit(gcStackMarkBit(i));
} else{
wrDigit(0);
}
}
wr('\n');
wr("mgis[pc=");
wrSmall(pc);
wr("]:");
for(int i = 31;i>=0;i--){ // @WCA loop=32
if((i+1)%8==0 && i<31){
wr('_');
}
if(i<gcMaxLocals()){
wrDigit(gcLocalMarkBit(i));
} else {
wrDigit(0);
}
}
wr('\n');
wr("local ref bits:\n");
for(int i=0;i<gcMaxLocals();i++){ // @WCA loop=32
wr("stack[");
wrSmall(vp+i);
wr("]:");
wrDigit(roots[vp+i-128]);
wr("\n");
}
wr("operand ref bits:\n");
for(int i=0;i<gcMaxStack();i++){ // @WCA loop=32
wr("stack[");
wrSmall(fp+5+i);
wr("]:");
wrDigit(roots[fp+5+i-128]);
wr("\n");
}
wr('\n');
}
static void wrroots(int num){
wr("--Complete stack for RtThread no. ");
wrSmall(num);
wr("--\n");
for(int i=0;i<MAXSTACK;i++){ // @WCA loop=128
wr("stack[");
wrSmall(i+128);
wr("]:");
wrDigit(roots[i]);
wr("\n");
}
}
static void wrByte(int i) {
wr('0' + i / 100);
wr('0' + i / 10 % 10);
wr('0' + i % 10);
wr(' ');
}
static void wrSmall(int i) {
wr('0' + i / 10000 % 10);
wr('0' + i / 1000 % 10);
wr('0' + i / 100 % 10);
wr('0' + i / 10 % 10);
wr('0' + i % 10);
}
static void wrDigit(int i) {
wr('0' + i % 10);
}
static void wr(int c) {
if (true) {
// while ((Native.rd(Const.IO_STATUS) & 1) == 0)
// ;
Native.wr(c, 0);
}
}
static void wr(String s) {
int i = s.length();
// if(i>80)
// System.out.println("String too long...");
for (int j = 0; j < i; ++j) { // @WCA loop=80
wr(s.charAt(j));
}
}
*/
//gc unpacking
static int gcStackMark(){
return (gcpack&0x01);//STACKMARKLEN
}
static int gcLocalMark(){
return ((gcpack>>>STACKMARKLEN)&0x01);//LOCALMARKLEN
}
static int gcMaxLocals(){
return ((gcpack>>>(STACKMARKLEN+LOCALMARKLEN))&0x1F);//MAXLOCALSLEN
}
static int gcMaxStack(){
return ((gcpack>>>(MAXLOCALSLEN+STACKMARKLEN+LOCALMARKLEN))&0x1F);//MAXSTACKLEN
}
static int gcInstr(){
return ((gcpack>>>(MAXSTACKLEN+MAXLOCALSLEN+STACKMARKLEN+LOCALMARKLEN))&0x03FF);//INSTRLEN
}
static int gcUniCnt(){
return ((gcpack>>>(INSTRLEN+MAXSTACKLEN+MAXLOCALSLEN+STACKMARKLEN+LOCALMARKLEN))&0x03FF); //UNICNTLEN
}
// in words
static int gcLength(){
int wordcnt;
// how wide is index
int num = 1;
indexbits = 0;
for(int i=1;i<32;i++){ // @WCA loop=31
if(num<unicnt){
num = (num<<1)|1;
} else
{
indexbits = i;
break;
}
}
if(gcStackMark()==1 || gcLocalMark()==1){
int pos = instr*indexbits + unicnt*(mstk+mloc);
wordcnt = pos >> 5;
if((pos & 0x1F)>0){
wordcnt++;
}
} else{
wordcnt = 0;
}
return wordcnt;
}
// prepare the stack and local mark words
// called once for each frame
static void setMarkWords(){
stackmarkword = localmarkword = 0;
// wr("inside setMarkWords\n");
if(gcLocalMark()==1 || gcStackMark() ==1){ // is there info
//read the index
int index = 0;
int indexpos = pc*indexbits;
for(int j=0;j<indexbits;j++){ // @WCA loop=31
int wordindex = (indexpos+j) >> 5; // div 32
int offset = (indexpos+j) & 0x1F; // mod 32
int val = Native.rdMem(infoaddr+wordindex);
int bit = (val>>>offset) & 0x01;
//System.out.print("val ");
//bitStr(val);
//System.out.println("");
//System.out.print("infoaddr ");
//System.out.println(infoaddr);
//System.out.print("wordindex ");
//System.out.println(wordindex);
//System.out.print("offset ");
//System.out.println(offset);
//System.out.print("indexpos ");
//System.out.println(indexpos);
//System.out.print("indexbits ");
//System.out.println(indexbits);
//System.out.print("bit ");
//System.out.print(j);
//System.out.print(" ");
//System.out.println(bit);
index |= (bit<<j);
}
//System.out.print("p:");
//System.out.println(index);
//read the corresponding unique pattern
indexpos = instr*indexbits+index*(mloc+mstk);
int oldwordindex = -1;
int val = -1;
for(int j=0;j<(mloc+mstk);j++){ // @WCA loop=32
// indexpos = inst*indexbits+index*(gcMaxLocals()+gcMaxStack())+j;
int wordindex = (indexpos+j)>>5; // /32
int offset = (indexpos+j) & 0x1F;
if(oldwordindex != wordindex){
val = Native.rdMem(infoaddr+wordindex);
}
oldwordindex = wordindex;
int bit = (val>>>offset) & 0x01;
if(j<mstk){ // stack marks
stackmarkword |= bit<<j;
}
else { // local marks
localmarkword |= bit<<(j-mstk);
}
}
}
}
/**
* 1 if the stack has a reference on the <code>index</code> position.
*/
static int gcStackMarkBit(int index){
if(index>mstk){
//System.out.println("index too big");
//System.exit(-1);
}
return (stackmarkword>>>index)&0x01;
}
/**
* 1 if the locals has a reference on the <code>index</code> position.
*/
public static int gcLocalMarkBit(int index){
if(index>mloc){
//System.out.println("index too big");
//System.exit(-1);
}
return (localmarkword>>>index)&0x01;
}
// Note that we write low order bits first.
/* static void bitStr(int word){
int mask = 0x01;
//for(int i = 31;i>=0;i--){
for(int i = 0;i<32;i++){ // @WCA loop=32
int res = (word>>>i) & mask;
if((i+1)%8==0 && i<31){
wr('_');
}
if(res==1){
wr('1');
}
else{
wr('0');
}
}
}*/
}