1 pnkfelix 1.1.2.1 // LiveTemps.java, created Mon Nov 8 23:35:55 1999 by pnkfelix 2 pnkfelix 1.1.2.1 // Copyright (C) 1999 Felix S. Klock II <pnkfelix@mit.edu> 3 pnkfelix 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 pnkfelix 1.1.2.1 package harpoon.Analysis.DataFlow; 5 pnkfelix 1.1.2.1 6 pnkfelix 1.1.2.1 import harpoon.Analysis.BasicBlock; 7 pnkfelix 1.1.2.9 import harpoon.IR.Properties.UseDefer; 8 pnkfelix 1.1.2.18 import harpoon.ClassFile.HCode; 9 pnkfelix 1.1.2.2 import harpoon.ClassFile.HCodeElement; 10 pnkfelix 1.1.2.1 import harpoon.Temp.Temp; 11 duncan 1.1.2.3 import harpoon.Util.CloneableIterator; 12 duncan 1.1.2.3 import harpoon.Util.Util; 13 cananian 1.6 import net.cscott.jutil.BitSetFactory; 14 cananian 1.6 import net.cscott.jutil.ReverseIterator; 15 cananian 1.6 import net.cscott.jutil.SetFactory; 16 pnkfelix 1.1.2.1 17 pnkfelix 1.1.2.1 import java.util.Set; 18 pnkfelix 1.1.2.1 import java.util.Map; 19 pnkfelix 1.1.2.1 import java.util.HashSet; 20 pnkfelix 1.1.2.1 import java.util.HashMap; 21 pnkfelix 1.1.2.1 import java.util.Iterator; 22 pnkfelix 1.1.2.1 23 pnkfelix 1.1.2.1 24 pnkfelix 1.1.2.1 /** 25 pnkfelix 1.1.2.1 * <code>LiveTemps</code> is an extension of <code>LiveVars</code> for 26 pnkfelix 1.1.2.1 * performing liveness analysis on <code>Temp</code>s. 27 pnkfelix 1.1.2.1 * 28 pnkfelix 1.1.2.1 * @author Felix S. Klock II <pnkfelix@mit.edu> 29 cananian 1.7 * @version $Id: LiveTemps.java,v 1.7 2004/02/08 03:19:21 cananian Exp $ 30 pnkfelix 1.1.2.1 */ 31 pnkfelix 1.1.2.12 public class LiveTemps extends LiveVars.BBVisitor { 32 pnkfelix 1.1.2.6 // may be null; code using this should check 33 pnkfelix 1.1.2.6 private Set liveOnProcExit; 34 pnkfelix 1.1.2.9 35 pnkfelix 1.1.2.19 protected SetFactory mySetFactory; 36 pnkfelix 1.1.2.9 37 pnkfelix 1.1.2.9 // calculates use/def information for the IR passed in. 38 pnkfelix 1.1.2.19 protected UseDefer ud; 39 pnkfelix 1.1.2.18 40 pnkfelix 1.1.2.18 /** Produces a default live variable analysis object and solves 41 pnkfelix 1.1.2.21 it. Uses <code>ud</code> to define Temp references in 42 pnkfelix 1.1.2.21 elements of <code>code</code>. elements in <code>code</code> 43 pnkfelix 1.1.2.21 must implement <code>CFGraphable</code>, and 44 pnkfelix 1.1.2.21 <code>liveOnExit</code> must be a Set of Temps (mapped to by 45 pnkfelix 1.1.2.21 <code>ud</code>) that are live on exit from 46 pnkfelix 1.1.2.21 <code>code</code>. 47 pnkfelix 1.1.2.18 */ 48 pnkfelix 1.1.2.21 public static LiveTemps make(HCode code, UseDefer ud, 49 pnkfelix 1.1.2.21 Set liveOnExit) { 50 pnkfelix 1.1.2.18 BasicBlock.Factory bbf = new BasicBlock.Factory(code); 51 pnkfelix 1.1.2.21 LiveTemps lt = new LiveTemps(bbf, liveOnExit, ud); 52 pnkfelix 1.1.2.18 Solver.worklistSolve 53 pnkfelix 1.1.2.18 // (bbFact.preorderBlocksIter(), 54 cananian 1.5 (new ReverseIterator(bbf.postorderBlocksIter()), lt); 55 pnkfelix 1.1.2.18 return lt; 56 pnkfelix 1.1.2.27 } 57 pnkfelix 1.1.2.27 58 pnkfelix 1.1.2.27 /** Finds the fixed-point solution for this LiveTemps. 59 pnkfelix 1.1.2.27 (Don't know why its taken me so long to realize 60 pnkfelix 1.1.2.27 that this belonged in here... procedural abstraction, awwwww yeah). 61 pnkfelix 1.1.2.27 */ 62 pnkfelix 1.1.2.27 public void solve() { 63 pnkfelix 1.1.2.27 Solver.worklistSolve 64 cananian 1.5 (new ReverseIterator(bbFact.postorderBlocksIter()), this); 65 pnkfelix 1.1.2.21 } 66 pnkfelix 1.1.2.21 67 pnkfelix 1.1.2.21 /** Produces a default live variable analysis object and solves 68 pnkfelix 1.1.2.21 it. elements in <code>code</code> must implement 69 cananian 1.1.2.23 <code>UseDefable</code>, <code>CFGraphable</code>, etc, and 70 pnkfelix 1.1.2.21 <code>liveOnExit</code> must be a Set of Temps that are live 71 pnkfelix 1.1.2.21 on exit from <code>code</code>. 72 pnkfelix 1.1.2.21 */ 73 pnkfelix 1.1.2.21 public static LiveTemps make(HCode code, Set liveOnExit) { 74 pnkfelix 1.1.2.21 return make(code, UseDefer.DEFAULT, liveOnExit); 75 pnkfelix 1.1.2.18 } 76 pnkfelix 1.1.2.1 77 pnkfelix 1.1.2.1 /** Constructs a new <code>LiveTemps</code> for <code>basicblocks</code>. 78 pnkfelix 1.1.2.1 <BR> <B>requires:</B> <OL> 79 pnkfelix 1.1.2.1 <LI> <code>basicblocks</code> is a 80 pnkfelix 1.1.2.1 <code>Iterator</code> of <code>BasicBlock</code>s, 81 pnkfelix 1.1.2.9 <LI> <code>ud</code> contains use/def information for all 82 pnkfelix 1.1.2.9 of all of the instructions in 83 pnkfelix 1.1.2.9 <code>basicblocks</code>. 84 pnkfelix 1.1.2.1 <LI> No element of <code>basicblocks</code> links to a 85 pnkfelix 1.1.2.1 <code>BasicBlock</code> not contained within 86 pnkfelix 1.1.2.1 <code>basicblocks</code> 87 pnkfelix 1.1.2.1 <LI> No <code>BasicBlock</code> is repeatedly iterated 88 pnkfelix 1.1.2.1 by <code>basicblocks</code> 89 pnkfelix 1.1.2.1 </OL> 90 pnkfelix 1.1.2.1 <BR> <B>modifies:</B> <code>basicblocks</code> 91 pnkfelix 1.1.2.1 <BR> <B>effects:</B> constructs a new 92 pnkfelix 1.1.2.1 <code>BasicBlockVisitor</code> and initializes its 93 pnkfelix 1.1.2.1 internal datasets for analysis of the 94 pnkfelix 1.1.2.1 <code>BasicBlock</code>s in <code>basicblocks</code>, 95 pnkfelix 1.1.2.1 iterating over all of <code>basicblocks</code> in the 96 pnkfelix 1.1.2.1 process. 97 pnkfelix 1.1.2.1 @param basicblocks <code>Iterator</code> of <code>BasicBlock</code>s to be analyzed. 98 pnkfelix 1.1.2.1 @param liveOnProcExit <code>Set</code> of <code>Temp</code>s that are live on exit from the method (for example, r0 for assembly code). 99 pnkfelix 1.1.2.1 */ 100 pnkfelix 1.1.2.13 public LiveTemps(BasicBlock.Factory bbFact, Set liveOnProcExit, 101 pnkfelix 1.1.2.9 UseDefer ud) { 102 pnkfelix 1.1.2.15 super(bbFact, false); 103 pnkfelix 1.1.2.11 this.ud = ud; 104 pnkfelix 1.1.2.11 105 pnkfelix 1.1.2.6 // duplicating code from LiveVars.java 106 pnkfelix 1.1.2.13 Set universe = findUniverse(bbFact.blockSet()); 107 pnkfelix 1.1.2.7 universe.addAll(liveOnProcExit); 108 pnkfelix 1.1.2.9 109 pnkfelix 1.1.2.25 if (false) { 110 pnkfelix 1.1.2.25 // FSK: cannot do this (yet) because universe is made up 111 pnkfelix 1.1.2.25 // of Temps from different sources (backend 112 pnkfelix 1.1.2.25 // register-temp-factory versus hmethod temp-factory), 113 pnkfelix 1.1.2.25 // resulting in index collisions. 114 pnkfelix 1.1.2.25 // Look into making a CompositeIndexer later that can 115 pnkfelix 1.1.2.25 // combine the two indexers; for now go back to the 116 pnkfelix 1.1.2.25 // built-in default. 117 pnkfelix 1.1.2.25 mySetFactory = new BitSetFactory(universe, Temp.INDEXER); 118 pnkfelix 1.1.2.25 } else { 119 pnkfelix 1.1.2.25 mySetFactory = new BitSetFactory(universe); 120 pnkfelix 1.1.2.25 } 121 pnkfelix 1.1.2.6 122 pnkfelix 1.1.2.6 // KEY difference: set liveOnProcExit before calling initBBtoLVI 123 pnkfelix 1.1.2.6 this.liveOnProcExit = liveOnProcExit; 124 pnkfelix 1.1.2.6 125 pnkfelix 1.1.2.13 initializeBBtoLVI( bbFact.blockSet(), mySetFactory ); 126 pnkfelix 1.1.2.1 } 127 pnkfelix 1.1.2.1 128 pnkfelix 1.1.2.13 public LiveTemps(BasicBlock.Factory bbFact, Set liveOnProcExit) { 129 pnkfelix 1.1.2.13 this(bbFact, liveOnProcExit, UseDefer.DEFAULT); 130 pnkfelix 1.1.2.9 } 131 duncan 1.1.2.3 132 pnkfelix 1.1.2.1 /** Constructor for LiveVars that allows the user to pass in their 133 pnkfelix 1.1.2.1 own <code>SetFactory</code> for constructing sets of the 134 pnkfelix 1.1.2.1 <code>Temp</code>s in the analysis. 135 pnkfelix 1.1.2.1 <BR> <B>requires:</B> All <code>Temp</code>s in 136 pnkfelix 1.1.2.1 <code>basicBlocks</code> are members of the universe for 137 pnkfelix 1.1.2.1 <code>tempSetFact</code>. 138 pnkfelix 1.1.2.1 139 pnkfelix 1.1.2.1 <BR> Doc TODO: Add all of the above documentation from the 140 pnkfelix 1.1.2.1 standard ctor. 141 pnkfelix 1.1.2.1 */ 142 pnkfelix 1.1.2.13 public LiveTemps(BasicBlock.Factory bbFact, 143 pnkfelix 1.1.2.1 Set liveOnProcExit, 144 pnkfelix 1.1.2.9 SetFactory tempSetFact, 145 pnkfelix 1.1.2.9 UseDefer ud) { 146 pnkfelix 1.1.2.9 // calling "special" ctor so that I can set up 147 pnkfelix 1.1.2.9 // liveOnProcExit before calling anything else. 148 pnkfelix 1.1.2.15 super(bbFact, false); 149 pnkfelix 1.1.2.9 150 pnkfelix 1.1.2.9 this.ud = ud; 151 pnkfelix 1.1.2.9 152 pnkfelix 1.1.2.9 mySetFactory = tempSetFact; 153 pnkfelix 1.1.2.9 154 pnkfelix 1.1.2.9 // KEY difference: set liveOnProcExit before calling initBBtoLVI 155 pnkfelix 1.1.2.9 this.liveOnProcExit = liveOnProcExit; 156 pnkfelix 1.1.2.9 157 pnkfelix 1.1.2.13 initializeBBtoLVI( bbFact.blockSet(), tempSetFact ); 158 pnkfelix 1.1.2.2 } 159 pnkfelix 1.1.2.2 160 pnkfelix 1.1.2.2 /** Returns the <code>Set</code> of <code>Temp</code>s that are 161 pnkfelix 1.1.2.2 live on on entry to <code>hce</code>. 162 pnkfelix 1.1.2.2 <BR> <B>requires:</B> A DataFlow Equation Solver has been run 163 pnkfelix 1.1.2.2 to completion on the graph of <code>BasicBlock</code>s 164 pnkfelix 1.1.2.2 containing some block that contains <code>hce</code>, 165 pnkfelix 1.1.2.2 with <code>this</code> as the 166 pnkfelix 1.1.2.2 <code>DataFlowBasicBlockVisitor</code>. 167 pnkfelix 1.1.2.2 <BR> <B>effects:</B> Returns a <code>Set</code> of 168 pnkfelix 1.1.2.2 <code>Temp</code>s that are live on entry to 169 pnkfelix 1.1.2.2 <code>hce</code>. 170 pnkfelix 1.1.2.2 */ 171 pnkfelix 1.1.2.2 public Set getLiveBefore(HCodeElement hce) { 172 pnkfelix 1.1.2.11 // live_before(hce) <-- 173 pnkfelix 1.1.2.11 // UNION( USE(hce), (live_after(hce) - DEF(hce))) 174 pnkfelix 1.1.2.11 Set liveBefore = mySetFactory.makeSet(this.getLiveAfter(hce)); 175 pnkfelix 1.1.2.11 liveBefore.removeAll(ud.defC(hce)); 176 pnkfelix 1.1.2.9 liveBefore.addAll(ud.useC(hce)); 177 duncan 1.1.2.3 178 duncan 1.1.2.3 return liveBefore; 179 pnkfelix 1.1.2.2 } 180 duncan 1.1.2.3 181 pnkfelix 1.1.2.2 /** Returns the <code>Set</code> of <code>Temp</code>s that are 182 pnkfelix 1.1.2.2 live on exit from <code>hce</code>. 183 pnkfelix 1.1.2.2 <BR> <B>requires:</B> A DataFlow Equation Solver has been run 184 pnkfelix 1.1.2.2 to completion on the graph of <code>BasicBlock</code>s 185 pnkfelix 1.1.2.2 containing some block that contains <code>hce</code>, 186 pnkfelix 1.1.2.2 with <code>this</code> as the 187 pnkfelix 1.1.2.2 <code>DataFlowBasicBlockVisitor</code>. 188 pnkfelix 1.1.2.2 <BR> <B>effects:</B> Returns a <code>Set</code> of 189 pnkfelix 1.1.2.2 <code>Temp</code>s that are live on exit from 190 pnkfelix 1.1.2.2 <code>hce</code>. 191 pnkfelix 1.1.2.2 */ 192 pnkfelix 1.1.2.2 public Set getLiveAfter(HCodeElement hce) { 193 pnkfelix 1.1.2.11 // System.out.println("FSK: getLiveAfter called"); 194 duncan 1.1.2.3 195 pnkfelix 1.1.2.13 BasicBlock bb = bbFact.getBlock(hce); 196 cananian 1.3.2.1 assert bb != null : "Code " + hce + " is not in a bb"; 197 pnkfelix 1.1.2.19 198 pnkfelix 1.1.2.11 Set liveAfter = 199 pnkfelix 1.1.2.11 mySetFactory.makeSet(this.getLiveOnExit(bb)); 200 pnkfelix 1.1.2.9 201 pnkfelix 1.1.2.9 // Starting from the last element in hce's basic block, 202 pnkfelix 1.1.2.9 // traverse the block in reverse order, until hce is 203 pnkfelix 1.1.2.9 // reached. Each step updates the liveness information. 204 pnkfelix 1.1.2.9 205 pnkfelix 1.1.2.17 java.util.List stms = bb.statements(); 206 pnkfelix 1.1.2.17 // System.out.print(" M"+stms.size()); 207 pnkfelix 1.1.2.17 java.util.ListIterator iter = stms.listIterator(stms.size()); 208 pnkfelix 1.1.2.11 209 pnkfelix 1.1.2.11 while(iter.hasPrevious()) { 210 pnkfelix 1.1.2.11 HCodeElement current = (HCodeElement) iter.previous(); 211 pnkfelix 1.1.2.11 212 pnkfelix 1.1.2.11 // System.out.println("doing live after for "+current); 213 pnkfelix 1.1.2.11 214 pnkfelix 1.1.2.19 if (hce == current) { 215 pnkfelix 1.1.2.19 return mySetFactory.makeSet(liveAfter); 216 pnkfelix 1.1.2.19 } 217 pnkfelix 1.1.2.9 218 pnkfelix 1.1.2.9 // update set for before 'current' 219 pnkfelix 1.1.2.9 liveAfter.removeAll(ud.defC(current)); 220 pnkfelix 1.1.2.16 liveAfter.addAll(ud.useC(current)); 221 pnkfelix 1.1.2.9 } 222 pnkfelix 1.1.2.19 223 pnkfelix 1.1.2.19 throw new RuntimeException("while loop reached end!!!"); 224 pnkfelix 1.1.2.19 225 pnkfelix 1.1.2.11 226 pnkfelix 1.1.2.1 } 227 pnkfelix 1.1.2.1 228 pnkfelix 1.1.2.1 /** Constructs a <code>Set</code> of all of the <code>Temp</code>s 229 pnkfelix 1.1.2.1 in <code>blocks</code>. 230 pnkfelix 1.1.2.1 <BR> <B>requires:</B> <OL> 231 pnkfelix 1.1.2.1 <LI> <code>blocks</code> is an <code>Iterator</code> of 232 pnkfelix 1.1.2.1 <code>BasicBlock</code>s. 233 pnkfelix 1.1.2.1 </OL> 234 pnkfelix 1.1.2.1 <BR> <B>modifies:</B> <code>blocks</code> 235 pnkfelix 1.1.2.1 <BR> <B>effects:</B> Iterates through all of the instructions 236 pnkfelix 1.1.2.1 contained in each element of <code>blocks</code>, adding 237 pnkfelix 1.1.2.1 each instruction's useC() and defC() to a universe of 238 pnkfelix 1.1.2.1 values, returning the universe after all of the 239 pnkfelix 1.1.2.1 instructions have been visited. 240 pnkfelix 1.1.2.1 */ 241 pnkfelix 1.1.2.13 protected Set findUniverse(Set blockSet) { 242 pnkfelix 1.1.2.13 Iterator blocks = blockSet.iterator(); 243 pnkfelix 1.1.2.1 HashSet temps = new HashSet(); 244 pnkfelix 1.1.2.1 while(blocks.hasNext()) { 245 pnkfelix 1.1.2.1 BasicBlock bb = (BasicBlock) blocks.next(); 246 cananian 1.7 for (Object hO : bb.statements()) { 247 cananian 1.7 HCodeElement h = (HCodeElement) hO; 248 pnkfelix 1.1.2.9 temps.addAll(ud.useC(h)); 249 pnkfelix 1.1.2.9 temps.addAll(ud.defC(h)); 250 pnkfelix 1.1.2.1 } 251 pnkfelix 1.1.2.1 } 252 pnkfelix 1.1.2.1 return temps; 253 pnkfelix 1.1.2.1 } 254 pnkfelix 1.1.2.1 255 pnkfelix 1.1.2.1 /** Initializes the USE/DEF information for 'bb' and stores in in 256 pnkfelix 1.1.2.1 the returned <code>LiveVarInfo</code>. 257 pnkfelix 1.1.2.1 */ 258 pnkfelix 1.1.2.1 protected LiveVarInfo makeUseDef(BasicBlock bb, SetFactory sf) { 259 pnkfelix 1.1.2.1 LiveVarInfo info = new LiveVarInfo(sf); 260 pnkfelix 1.1.2.6 261 pnkfelix 1.1.2.8 if (liveOnProcExit != null && 262 pnkfelix 1.1.2.8 bb.nextLength() == 0) { 263 pnkfelix 1.1.2.8 264 pnkfelix 1.1.2.8 // Check that last instr is a method exit point 265 pnkfelix 1.1.2.8 // System.out.println("FSK found last bb: " + bb.getLast()); 266 pnkfelix 1.1.2.8 267 pnkfelix 1.1.2.6 info.lvOUT.addAll(liveOnProcExit); 268 pnkfelix 1.1.2.6 info.lvIN.addAll(liveOnProcExit); 269 pnkfelix 1.1.2.6 } 270 pnkfelix 1.1.2.6 271 pnkfelix 1.1.2.10 Iterator instrs = bb.statements().listIterator(); 272 pnkfelix 1.1.2.1 273 pnkfelix 1.1.2.26 if (LiveVars.DEBUG) 274 pnkfelix 1.1.2.26 System.out.println(bb+" use:"+info.use+" def:"+info.def); 275 pnkfelix 1.1.2.26 276 pnkfelix 1.1.2.1 while (instrs.hasNext()) { 277 pnkfelix 1.1.2.9 HCodeElement h = (HCodeElement) instrs.next(); 278 pnkfelix 1.1.2.1 279 pnkfelix 1.1.2.1 // check for usage before definition, to handle the case 280 pnkfelix 1.1.2.1 // of a <- a+1 (which should lead to a USE(a), *not* a DEF 281 pnkfelix 1.1.2.1 282 pnkfelix 1.1.2.1 // USE: set of vars used in block before being defined 283 pnkfelix 1.1.2.9 for(int i=0; i<ud.use(h).length; i++) { 284 pnkfelix 1.1.2.9 Temp t = ud.use(h)[i]; 285 pnkfelix 1.1.2.1 if ( !info.def.contains(t) ) { 286 pnkfelix 1.1.2.26 boolean changed = info.use.add(t); 287 pnkfelix 1.1.2.26 if (LiveVars.DEBUG) { 288 pnkfelix 1.1.2.26 System.out.println("adding use:"+t+" from "+h); 289 pnkfelix 1.1.2.26 } 290 pnkfelix 1.1.2.1 } 291 pnkfelix 1.1.2.1 } 292 pnkfelix 1.1.2.1 // DEF: set of vars defined in block before being used 293 pnkfelix 1.1.2.9 for(int i=0; i<ud.def(h).length; i++) { 294 pnkfelix 1.1.2.9 Temp t = ud.def(h)[i]; 295 pnkfelix 1.1.2.1 if ( !info.use.contains(t) ) { 296 pnkfelix 1.1.2.26 boolean changed = info.def.add(t); 297 pnkfelix 1.1.2.26 if (LiveVars.DEBUG) { 298 pnkfelix 1.1.2.26 System.out.println("adding def:"+t+" from "+h); 299 pnkfelix 1.1.2.26 } 300 pnkfelix 1.1.2.1 } 301 pnkfelix 1.1.2.1 } 302 pnkfelix 1.1.2.1 } 303 pnkfelix 1.1.2.26 304 pnkfelix 1.1.2.26 if (LiveVars.DEBUG) 305 pnkfelix 1.1.2.26 System.out.println(bb+" use:"+info.use+" def:"+info.def); 306 pnkfelix 1.1.2.26 307 pnkfelix 1.1.2.1 return info; 308 pnkfelix 1.1.2.24 } 309 pnkfelix 1.1.2.24 310 pnkfelix 1.1.2.24 /** Returns a String containing a human-readable version of the 311 pnkfelix 1.1.2.24 analysis results. 312 pnkfelix 1.1.2.24 */ 313 pnkfelix 1.1.2.24 public String dumpElems() { 314 pnkfelix 1.1.2.24 StringBuffer sb = new StringBuffer(); 315 pnkfelix 1.1.2.24 sb.append("\t LIVE ON EXIT:"+liveOnProcExit+"\n"); 316 pnkfelix 1.1.2.24 317 pnkfelix 1.1.2.24 sb.append("\t START LiveVarInfos:\n"+ dump(false)); 318 pnkfelix 1.1.2.24 319 pnkfelix 1.1.2.24 320 pnkfelix 1.1.2.24 sb.append("\t FINIS LiveVarInfos"); 321 pnkfelix 1.1.2.24 int j = 0; 322 pnkfelix 1.1.2.24 for(Iterator i=bbFact.getHCode().getElementsI(); i.hasNext();){ 323 pnkfelix 1.1.2.24 HCodeElement h = (HCodeElement) i.next(); 324 pnkfelix 1.1.2.24 sb.append(j+"\t"+h.toString()+"\n"); 325 pnkfelix 1.1.2.24 sb.append("\t"+"USES:"+ud.useC(h)+"\tDEFS:"+ud.defC(h)); 326 pnkfelix 1.1.2.26 if (bbFact.getBlock(h)==null) { 327 pnkfelix 1.1.2.26 sb.append("\t(NO BASIC BLOCK)\n"); 328 pnkfelix 1.1.2.26 } else { 329 pnkfelix 1.1.2.26 sb.append("\tLIVE-AFTER:"+getLiveAfter(h)+"\n"); 330 pnkfelix 1.1.2.26 } 331 pnkfelix 1.1.2.24 j++; 332 pnkfelix 1.1.2.24 } 333 pnkfelix 1.1.2.24 return sb.toString(); 334 pnkfelix 1.1.2.1 } 335 cananian 1.2 }