/* 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 com.jopdesign.sys; import util.Timer; import joprt.RtThread; import com.jopdesign.sys.Const; import com.jopdesign.sys.GC; import com.jopdesign.sys.Native; import com.jopdesign.sys.JVMHelp; // 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 (MAXSTACK==128) throw new Error("GCStkWalk needs to be updated for configurable stack size"); 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. 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 while (fp > 128 + 5) { // stop befor 'first' method // saved vars of curent frame that points to // previous frame. See Fig. 6.2 in ms thesis 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: This is not good for WCET. 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 = gcMaxLocals(); mstk = gcMaxStack(); unicnt = gcUniCnt(); instr = 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++){ // 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++){ // 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--){ 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--){ 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++){ 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++){ 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++){ 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, Const.IO_UART); } } static void wr(String s) { int i = s.length(); for (int j = 0; j < i; ++j) { 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++){ 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++){ 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++){ // 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. */ 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++){ int res = (word>>>i) & mask; if((i+1)%8==0 && i<31){ wr('_'); } if(res==1){ wr('1'); } else{ wr('0'); } } } }