001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.ssa; 014 015import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH_opcode; 016import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_ADDR_opcode; 017import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_INT_opcode; 018import static org.jikesrvm.compilers.opt.ir.Operators.BBEND_opcode; 019import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode; 020import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode; 021import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD_opcode; 022import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE_opcode; 023import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode; 024import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode; 025import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode; 026import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD_opcode; 027import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE_opcode; 028import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode; 029import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode; 030import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode; 031import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode; 032import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode; 033import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode; 034import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD_opcode; 035import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE_opcode; 036import static org.jikesrvm.compilers.opt.ir.Operators.LABEL_opcode; 037import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode; 038import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode; 039import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD_opcode; 040import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE_opcode; 041import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER_opcode; 042import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT_opcode; 043import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_UNRESOLVED_opcode; 044import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_opcode; 045import static org.jikesrvm.compilers.opt.ir.Operators.NEWOBJMULTIARRAY_opcode; 046import static org.jikesrvm.compilers.opt.ir.Operators.NEW_UNRESOLVED_opcode; 047import static org.jikesrvm.compilers.opt.ir.Operators.NEW_opcode; 048import static org.jikesrvm.compilers.opt.ir.Operators.PHI; 049import static org.jikesrvm.compilers.opt.ir.Operators.PHI_opcode; 050import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_ADDR_opcode; 051import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_INT_opcode; 052import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode; 053import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode; 054import static org.jikesrvm.compilers.opt.ir.Operators.READ_CEILING_opcode; 055import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode; 056import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode; 057import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD_opcode; 058import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE_opcode; 059import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode; 060import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode; 061import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD_opcode; 062import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE_opcode; 063import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode; 064import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode; 065import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD_opcode; 066import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_BEGIN_opcode; 067import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_END_opcode; 068import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode; 069import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD_opcode; 070import static org.jikesrvm.compilers.opt.ir.Operators.WRITE_FLOOR_opcode; 071 072import java.util.ArrayList; 073import java.util.Enumeration; 074import java.util.HashMap; 075import java.util.HashSet; 076import java.util.Iterator; 077import java.util.Set; 078 079import org.jikesrvm.VM; 080import org.jikesrvm.classloader.FieldReference; 081import org.jikesrvm.classloader.RVMField; 082import org.jikesrvm.classloader.TypeReference; 083import org.jikesrvm.compilers.opt.OperationNotImplementedException; 084import org.jikesrvm.compilers.opt.ir.ALoad; 085import org.jikesrvm.compilers.opt.ir.AStore; 086import org.jikesrvm.compilers.opt.ir.BBend; 087import org.jikesrvm.compilers.opt.ir.BasicBlock; 088import org.jikesrvm.compilers.opt.ir.GetField; 089import org.jikesrvm.compilers.opt.ir.GetStatic; 090import org.jikesrvm.compilers.opt.ir.GuardedUnary; 091import org.jikesrvm.compilers.opt.ir.IR; 092import org.jikesrvm.compilers.opt.ir.Instruction; 093import org.jikesrvm.compilers.opt.ir.Label; 094import org.jikesrvm.compilers.opt.ir.Phi; 095import org.jikesrvm.compilers.opt.ir.PutField; 096import org.jikesrvm.compilers.opt.ir.PutStatic; 097import org.jikesrvm.compilers.opt.ir.operand.BasicBlockOperand; 098import org.jikesrvm.compilers.opt.ir.operand.HeapOperand; 099import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; 100import org.jikesrvm.compilers.opt.ir.operand.Operand; 101 102/** 103 * An <code> SSADictionary </code> structure holds lookaside 104 * information regarding Heap Array SSA form for an IR. The general idea 105 * is that all Heap Array SSA form information resides in this lookaside 106 * structure. Note that this is not the case for scalar SSA information. 107 * 108 * <P> See our SAS 2000 paper 109 * <a href="http://www.research.ibm.com/jalapeno/publication.html#sas00"> 110 * Unified Analysis of Arrays and Object References in Strongly Typed 111 * Languages </a> for an overview of Array SSA form. More implementation 112 * details are documented in {@link SSA}. 113 * 114 * @see SSA 115 */ 116@SuppressWarnings("unchecked") 117// Generic HeapOperands and HeapVariables make this 118// impossible to typecheck properly 119public final class SSADictionary { 120 121 /** 122 * Flag to turn on debugging 123 */ 124 private static final boolean DEBUG = false; 125 126 /** 127 * The object for the heap variable that is used for modelling 128 * explicit exception dependencies 129 */ 130 static final String exceptionState = "X-State"; 131 132 /** 133 * A mapping from <code> Instruction </code> to the set of heap 134 * operands (an <code> HeapOperand[]</code>) that this instruction 135 * uses. Note that PHI instructions <STRONG> do not </STRONG> appear in 136 * this mapping. 137 */ 138 private final HashMap<Instruction, HeapOperand<Object>[]> uses = 139 new HashMap<Instruction, HeapOperand<Object>[]>(); 140 141 /** 142 * A mapping from <code> Instruction </code> to the set of heap 143 * operands (an <code> HeapOperand[]</code>) that this instruction 144 * defines. Note that PHI instructions <STRONG> do not </STRONG> appear in 145 * this mapping. 146 */ 147 private final HashMap<Instruction, HeapOperand<Object>[]> defs = 148 new HashMap<Instruction, HeapOperand<Object>[]>(); 149 150 /** 151 * A mapping from <code> HeapKey </code> to the set of heap 152 * variables introduced for this IR 153 */ 154 private final HashMap<HeapKey<Object>, HeapVariable<Object>> heapVariables = 155 new HashMap<HeapKey<Object>, HeapVariable<Object>>(); 156 157 /** 158 * A mapping from heap variable type to <code> Integer </code> 159 * This structure holds the next number to assign when creating 160 * a new heap variable name for a given type 161 */ 162 private final HashMap<Object, Integer> nextNumber = new HashMap<Object, Integer>(); 163 164 /** 165 * A mapping from <code> BasicBlock </code> to <code> ArrayList 166 * </code> of <code> Instruction </code>. 167 * This map holds the list of heap phi instructions stored as 168 * lookaside for each basic block. 169 */ 170 private final HashMap<BasicBlock, ArrayList<Instruction>> heapPhi = 171 new HashMap<BasicBlock, ArrayList<Instruction>>(10); 172 173 /** 174 * An empty vector, used for utility. 175 */ 176 private static final ArrayList<Instruction> emptyArrayList = new ArrayList<Instruction>(0); 177 178 /** 179 * A mapping from <code> HeapVariable </code> to <code> HashSet 180 * </code> of <code> HeapOperand </code>. 181 * This map holds the set of heap operands which use each heap 182 * variable. 183 */ 184 private final HashMap<HeapVariable<Object>, HashSet<HeapOperand<Object>>> UseChain = 185 new HashMap<HeapVariable<Object>, HashSet<HeapOperand<Object>>>(10); 186 187 /** 188 * A mapping from <code> HeapVariable </code> to <code> HeapOperand </code>. 189 * This map holds the set of heap operands which define each heap 190 * variable. 191 */ 192 private final HashMap<HeapVariable<Object>, HeapOperand<Object>> DefChain = 193 new HashMap<HeapVariable<Object>, HeapOperand<Object>>(10); 194 195 /** 196 * The set of instructions which have been registered to potentially 197 * exit the procedure 198 */ 199 private final HashSet<Instruction> exits = new HashSet<Instruction>(10); 200 201 /** 202 * A mapping from a heap variable type to a <code> HashSet 203 * </code> of <code> Instruction </code>. 204 * The set of all uses of a heap variable type 205 * <em> before </em> we performed renaming for SSA. 206 */ 207 private final HashMap<Object, HashSet<HeapOperand<Object>>> originalUses = 208 new HashMap<Object, HashSet<HeapOperand<Object>>>(10); 209 210 /** 211 * A mapping from a heap variable type to a <code> HashSet 212 * </code> of <code> Instruction </code>. 213 * The set of all definitions of a heap variable type 214 * <em> before </em> we performed renaming for SSA. 215 */ 216 private final HashMap<Object, HashSet<HeapOperand<Object>>> originalDefs = 217 new HashMap<Object, HashSet<HeapOperand<Object>>>(10); 218 219 /** 220 * The set of type to build heap array variables for 221 */ 222 private final Set<Object> heapTypes; 223 224 /** 225 * Should the heap array SSA form constructed include uphi functions? 226 * That is, does a <em> use </em> create a new name for a heap variable. 227 */ 228 private final boolean uphi; 229 230 /** 231 * Should PEIs and stores to the heap be modelled via an explicit exception 232 * state heap variable? 233 */ 234 private final boolean insertPEIDeps; 235 236 /** 237 * A pointer to the governing IR 238 */ 239 private final IR ir; 240 241 /** 242 * Initialize a structure to hold Heap Array SSA information. 243 * 244 * @param heapTypes only create heap arrays for these locations. 245 * if null, create all heap arrays 246 * @param uphi Should we use uphi functions? (ie. loads create a new 247 * name for heap arrays) 248 * @param insertPEIDeps whether to model PEIs and stores to the heap 249 * via an explicit exception state heap variable 250 * @param ir pointer back to the IR 251 */ 252 SSADictionary(Set<Object> heapTypes, boolean uphi, boolean insertPEIDeps, IR ir) { 253 this.heapTypes = heapTypes; 254 this.uphi = uphi; 255 this.insertPEIDeps = insertPEIDeps; 256 this.ir = ir; 257 } 258 259 /** 260 * Does a particular instruction <em> use </em> any heap variable? 261 * 262 * @param s the instruction in question 263 * @return true iff the instruction uses any heap variable. false 264 * otherwise 265 */ 266 boolean usesHeapVariable(Instruction s) { 267 // special case code for Phi instructions 268 if (Phi.conforms(s)) { 269 Operand result = Phi.getResult(s); 270 return (result instanceof HeapOperand); 271 } 272 HeapOperand<Object>[] o = uses.get(s); 273 return (o != null); 274 } 275 276 /** 277 * Does a particular instruction <em> define </em> any heap variable? 278 * 279 * @param s the instruction in question 280 * @return true iff the instruction defs any heap variable. false 281 * otherwise 282 */ 283 boolean defsHeapVariable(Instruction s) { 284 // special case code for Phi instructions 285 if (s.operator() == PHI) { 286 Operand result = Phi.getResult(s); 287 return (result instanceof HeapOperand); 288 } 289 HeapOperand<Object>[] o = defs.get(s); 290 return (o != null); 291 } 292 293 /** 294 * Return the heap operands used by an instruction. 295 * 296 * @param s the instruction in question 297 * @return an array of the heap operands this instruction uses 298 */ 299 public HeapOperand<Object>[] getHeapUses(Instruction s) { 300 if (s.operator() == PHI) { 301 if (!usesHeapVariable(s)) return null; 302 HeapOperand<Object>[] result = new HeapOperand[Phi.getNumberOfValues(s)]; 303 for (int i = 0; i < result.length; i++) { 304 result[i] = (HeapOperand) Phi.getValue(s, i); 305 } 306 return result; 307 } else { 308 return uses.get(s); 309 } 310 } 311 312 /** 313 * Return the heap operands defined by an instruction. 314 * 315 * @param s the instruction in question 316 * @return an array of the heap operands this instruction defs 317 */ 318 public HeapOperand<Object>[] getHeapDefs(Instruction s) { 319 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 320 return defs.get(s); 321 } 322 323 /** 324 * Return the number of heap operands defined by an instruction 325 * 326 * @param s the instruction in question 327 * @return the number of heap operands this instruction defs 328 */ 329 int getNumberOfHeapDefs(Instruction s) { 330 return getHeapDefs(s).length; 331 } 332 333 /** 334 * Replace all heap variables that an instruction defs with 335 * new heap variables. Each new heap variable has the same 336 * type as the old one, but a new number. Essentially, this 337 * function introduces new names required for translation 338 * into SSA form. This instruction will be the single static 339 * definition for each new heap variable. 340 * 341 * @param s the instruction that writes to the new heap variables 342 * @param b the basic block containing <code> s </code> 343 * @return the new heap variables that the instruction defines 344 */ 345 //@SuppressWarnings("unchecked") 346 HeapOperand<Object>[] replaceDefs(Instruction s, BasicBlock b) { 347 if (s.operator() == PHI) { 348 // Note that a PHI 349 // instruction defs exactly one heap variable, newH[0] 350 HeapOperand<Object> oldDef = (HeapOperand) Phi.getResult(s); 351 int number = getNextHeapVariableNumber(oldDef.getHeapType()); 352 HeapOperand<Object>[] newH = new HeapOperand[1]; 353 newH[0] = new HeapOperand<Object>(new HeapVariable<Object>(oldDef.getHeapType(), number, ir)); 354 newH[0].setInstruction(s); 355 Phi.setResult(s, newH[0]); 356 // record the new heap definition 357 newH[0].getHeapVariable().registerDef(b); 358 if (DEBUG) System.out.println("New heap def " + newH[0] + " for " + s); 359 // store the new heap variable in relevant data structures 360 HeapKey<Object> key = new HeapKey<Object>(number, oldDef.getHeapType()); 361 heapVariables.put(key, newH[0].getHeapVariable()); 362 return newH; 363 } else { 364 // get old heap operands defined by this instruction 365 HeapOperand<Object>[] oldH = defs.get(s); 366 HeapOperand<Object>[] newH = new HeapOperand[oldH.length]; 367 // for each old heap variable .. 368 for (int i = 0; i < oldH.length; i++) { 369 // create a new heap variable 370 int number = getNextHeapVariableNumber(oldH[i].getHeapType()); 371 newH[i] = new HeapOperand<Object>(new HeapVariable<Object>(oldH[i].getHeapType(), number, ir)); 372 newH[i].setInstruction(s); 373 // record the new heap definition 374 newH[i].getHeapVariable().registerDef(b); 375 if (DEBUG) System.out.println("New heap def " + newH[i] + " for " + s); 376 // store the new heap variable in relevant data structures 377 HeapKey<Object> key = new HeapKey<Object>(number, oldH[i].getHeapType()); 378 heapVariables.put(key, newH[i].getHeapVariable()); 379 } 380 // record the new heap variables this instruction defs 381 defs.put(s, newH); 382 return newH; 383 } 384 } 385 386 /** 387 * Return an enumeration of the heap variables in this IR. 388 * 389 * @return the heap variables stored for this IR 390 */ 391 Iterator<HeapVariable<Object>> getHeapVariables() { 392 return heapVariables.values().iterator(); 393 } 394 395 /** 396 * Return an enumeration of the control-phi functions for 397 * <em> Heap </em> variables at the beginning of a basic block. 398 * 399 * @param bb the basic block in question 400 * @return the phi instructions for heap variables at the beginning of 401 * the basic block 402 */ 403 public Iterator<Instruction> getHeapPhiInstructions(BasicBlock bb) { 404 ArrayList<Instruction> v = heapPhi.get(bb); 405 if (v == null) { 406 return emptyArrayList.iterator(); 407 } 408 return v.iterator(); 409 } 410 411 /** 412 * Return an enumeration of all instructions for a basic block, including 413 * the control-PHI functions for <em> heap </em> variables stored 414 * implicitly here. 415 * 416 * @param bb the basic block in question 417 * @return an enumeration of all instructions in this basic block, 418 * including heap phi instructions stored implicitly in this lookaside 419 * structure 420 */ 421 AllInstructionEnumeration getAllInstructions(BasicBlock bb) { 422 return new AllInstructionEnumeration(bb, this); 423 } 424 425 /** 426 * Return an enumeration of all uses of a particular heap variable. 427 * 428 * @param A the heap variable in question 429 * @return an iterator over all instructions that use this heap 430 * variable 431 */ 432 Iterator<HeapOperand<Object>> iterateHeapUses(HeapVariable<Object> A) { 433 HashSet<HeapOperand<Object>> u = UseChain.get(A); 434 return u.iterator(); 435 } 436 437 /** 438 * Return the operand that represents a heap variable's unique def. 439 * 440 * @param A the heap variable in question 441 * @return the heap operand that represents this heap variable's unique 442 * static definition 443 */ 444 HeapOperand<Object> getUniqueDef(HeapVariable<Object> A) { 445 return DefChain.get(A); 446 } 447 448 /** 449 * Return an enumeration of all the original uses of a heap variable. 450 * That is, return an iteration of all uses of the heap variable 451 * <em> before </em> we performed renaming for SSA. 452 * 453 * @param A the heap variable in question 454 * @return an iteration of all instructions that used this heap 455 * variable, prior to renaming for SSA 456 */ 457 @SuppressWarnings("unused") 458 // Useful for debugging ?? 459 private Iterator<HeapOperand<Object>> iterateOriginalHeapUses(HeapVariable<Object> A) { 460 Object type = A.getHeapType(); 461 HashSet<HeapOperand<Object>> set = findOrCreateOriginalUses(type); 462 return set.iterator(); 463 } 464 465 /** 466 * Return an enumeration of all the original definitions of a heap variable. 467 * That is, return an iteration of all defs of the heap variable 468 * <em> before </em> we performed renaming for SSA. 469 * 470 * @param A the heap variable in question 471 * @return an iteration of all instructions that defined this heap 472 * variable, prior to renaming for SSA 473 */ 474 @SuppressWarnings("unused") 475 // Useful for debugging ?? 476 private Iterator<HeapOperand<Object>> iterateOriginalHeapDefs(HeapVariable<Object> A) { 477 Object type = A.getHeapType(); 478 HashSet<HeapOperand<Object>> set = findOrCreateOriginalDefs(type); 479 return set.iterator(); 480 } 481 482 /** 483 * Return a set of all the original uses of a heap variable. 484 * That is, return the set of all uses of the heap variable 485 * <em> before </em> we performed renaming for SSA. 486 * 487 * @param type The heap variable in question 488 * @return the set of all instructions that used this heap 489 * variable, prior to renaming for SSA 490 */ 491 private HashSet<HeapOperand<Object>> findOrCreateOriginalUses(Object type) { 492 HashSet<HeapOperand<Object>> result = originalUses.get(type); 493 if (result != null) { 494 return result; 495 } 496 // not found: create a new set 497 result = new HashSet<HeapOperand<Object>>(2); 498 for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) { 499 HeapVariable<Object> B = e.next(); 500 if (B.getHeapType().equals(type)) { 501 HashSet<HeapOperand<Object>> u = UseChain.get(B); 502 result.addAll(u); 503 } 504 } 505 // store it in the hash set, and return 506 originalUses.put(type, result); 507 return result; 508 } 509 510 /** 511 * Return a set of all the original definitions of a heap variable. 512 * That is, return the set of all uses of the heap variable 513 * <em> before </em> we performed renaming for SSA. 514 * 515 * @param type the heap variable in question 516 * @return the set of all instructions that defined this heap 517 * variable, prior to renaming for SSA 518 */ 519 private HashSet<HeapOperand<Object>> findOrCreateOriginalDefs(Object type) { 520 HashSet<HeapOperand<Object>> result = originalDefs.get(type); 521 if (result != null) { 522 return result; 523 } 524 // not found: create a new set 525 result = new HashSet<HeapOperand<Object>>(2); 526 for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) { 527 HeapVariable<Object> B = e.next(); 528 if (B.getHeapType().equals(type)) { 529 HeapOperand<Object> def = getUniqueDef(B); 530 if (def != null) { 531 result.add(def); 532 } 533 } 534 } 535 // store it in the hash set, and return 536 originalDefs.put(type, result); 537 return result; 538 } 539 540 /** 541 * Return the number of uses of a heap variable. 542 * 543 * @param A the heap variable in question 544 * @return the number of uses of the heap variable 545 */ 546 int getNumberOfUses(HeapVariable<Object> A) { 547 HashSet<HeapOperand<Object>> u = UseChain.get(A); 548 return u.size(); 549 } 550 551 /** 552 * Return an enumeration of all heap variables that may be 553 * exposed on procedure exit. 554 * 555 * @return an enumeration of all heap variables that may be exposed on 556 * procedure exit 557 */ 558 Iterator<HeapVariable<Object>> enumerateExposedHeapVariables() { 559 ArrayList<HeapVariable<Object>> v = new ArrayList<HeapVariable<Object>>(); 560 for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) { 561 HeapVariable<Object> H = e.next(); 562 if (isExposedOnExit(H)) { 563 v.add(H); 564 } 565 } 566 return v.iterator(); 567 } 568 569 /** 570 * Checks whether a heap variable is exposed on procedure exit. 571 * 572 * @param H the heap variable 573 * @return {@code true} or {@code false} as appropriate 574 */ 575 boolean isExposedOnExit(HeapVariable<Object> H) { 576 for (Iterator<HeapOperand<Object>> i = iterateHeapUses(H); i.hasNext();) { 577 HeapOperand<Object> op = i.next(); 578 Instruction s = op.instruction; 579 if (exits.contains(s)) { 580 return true; 581 } 582 } 583 return false; 584 } 585 586 /** 587 * Recompute the chain of uses for each heap variable. 588 * NOTE: for now this procedure does <em> not </em> recompute 589 * def chains 590 */ 591 void recomputeArrayDU() { 592 UseChain.clear(); 593 DefChain.clear(); 594 // create a set of uses for each heap variable 595 for (Iterator<HeapVariable<Object>> e = getHeapVariables(); e.hasNext();) { 596 HeapVariable<Object> H = e.next(); 597 HashSet<HeapOperand<Object>> u = new HashSet<HeapOperand<Object>>(2); 598 UseChain.put(H, u); 599 } 600 // populate the use chain with each use registered 601 for (HeapOperand<Object>[] operands : uses.values()) { 602 if (operands == null) continue; 603 for (HeapOperand<Object> operand : operands) { 604 HeapVariable<Object> v = operand.getHeapVariable(); 605 HashSet<HeapOperand<Object>> u = UseChain.get(v); 606 u.add(operand); 607 } 608 } 609 // record the unique def for each heap variable 610 for (HeapOperand<Object>[] operands : defs.values()) { 611 if (operands == null) continue; 612 for (HeapOperand<Object> operand : operands) { 613 HeapVariable<Object> v = operand.getHeapVariable(); 614 DefChain.put(v, operand); 615 } 616 } 617 // handle each HEAP PHI function. 618 for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) { 619 BasicBlock bb = e.nextElement(); 620 for (Iterator<Instruction> hp = getHeapPhiInstructions(bb); hp.hasNext();) { 621 Instruction phi = hp.next(); 622 HeapOperand<Object> H = (HeapOperand) Phi.getResult(phi); 623 HeapVariable<Object> v = H.getHeapVariable(); 624 DefChain.put(v, H); 625 for (int i = 0; i < Phi.getNumberOfValues(phi); i++) { 626 HeapOperand<Object> Hu = (HeapOperand) Phi.getValue(phi, i); 627 HeapVariable<Object> vu = Hu.getHeapVariable(); 628 HashSet<HeapOperand<Object>> u = UseChain.get(vu); 629 u.add(Hu); 630 } 631 } 632 } 633 } 634 635 /** 636 * Delete an HeapOperand from the use chain of its heap variable 637 * 638 * @param op the heap operand to be deleted 639 */ 640 void deleteFromUseChain(HeapOperand<Object> op) { 641 HeapVariable<Object> hv = op.getHeapVariable(); 642 HashSet<HeapOperand<Object>> u = UseChain.get(hv); 643 u.remove(op); 644 } 645 646 /** 647 * Add an HeapOperand to the use chain of its heap variable 648 * 649 * @param op the heap operand to be added 650 */ 651 void addToUseChain(HeapOperand<Object> op) { 652 HeapVariable<Object> hv = op.getHeapVariable(); 653 HashSet<HeapOperand<Object>> u = UseChain.get(hv); 654 u.add(op); 655 } 656 657 /** 658 * Create a heap control phi instruction, and store it at the 659 * beginning of a basic block. 660 * 661 * @param bb the basic block 662 * @param H the heap variable to merge 663 */ 664 void createHeapPhiInstruction(BasicBlock bb, HeapVariable<Object> H) { 665 Instruction s = makePhiInstruction(H, bb); 666 /* 667 HeapOperand[] Hprime = new HeapOperand[1]; 668 Hprime[0] = new HeapOperand(H); 669 Hprime[0].setInstruction(s); 670 defs.put(s, Hprime); 671 */ 672 ArrayList<Instruction> heapPhis = heapPhi.get(bb); 673 if (heapPhis == null) { 674 heapPhis = new ArrayList<Instruction>(2); 675 heapPhi.put(bb, heapPhis); 676 } 677 heapPhis.add(s); 678 registerInstruction(s, bb); 679 } 680 681 /** 682 * Register that an instruction now uses the set of heap operands 683 * 684 * @param s the instruction in question 685 * @param H the set of heap operands which s uses 686 */ 687 void replaceUses(Instruction s, HeapOperand<Object>[] H) { 688 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 689 uses.put(s, H); 690 for (HeapOperand<Object> aH : H) { 691 aH.setInstruction(s); 692 } 693 } 694 695 /** 696 * Return the total number of heap variables allocated for the IR 697 * 698 * @return the total number of heap variables allocated for the IR 699 */ 700 int getNumberOfHeapVariables() { 701 return heapVariables.size(); 702 } 703 704 /** 705 * Register that an instruction s can potentially leave the procedure. 706 * We conservatively record that s uses all heap variables. 707 * <p> NOTE: This function should be called before renaming. 708 * <p> NOTE: Only need to use this for backwards analyses 709 * 710 * @param s the instruction in question 711 * @param b s's basic block 712 */ 713 @SuppressWarnings("unchecked") 714 void registerExit(Instruction s, BasicBlock b) { 715 // setup an array of all heap variables 716 // TODO: for efficiency, cache a copy of 'all' 717 Iterator<HeapVariable<Object>> vars = heapVariables.values().iterator(); 718 HeapOperand<Object>[] all = new HeapOperand[heapVariables.size()]; 719 for (int i = 0; i < all.length; i++) { 720 all[i] = new HeapOperand<Object>(vars.next()); 721 all[i].setInstruction(s); 722 // record that all[i] is def'ed in b 723 all[i].getHeapVariable().registerDef(b); 724 } 725 // record that s uses all heap variables 726 uses.put(s, all); 727 // record that instruction s can exit the procedure 728 exits.add(s); 729 } 730 731 /** 732 * Register that an instruction s has unknown side effects. That is, 733 * we conservatively record that s defs and uses all heap variables. 734 * <p> NOTE: This function should be called before renaming. 735 * 736 * @param s the instruction in question 737 * @param b the basic block containing s 738 */ 739 @SuppressWarnings("unchecked") 740 void registerUnknown(Instruction s, BasicBlock b) { 741 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 742 // setup an array of all heap variables 743 // TODO: for efficiency, cache a copy of 'all' 744 Iterator vars = heapVariables.values().iterator(); 745 HeapOperand<Object>[] all = new HeapOperand[heapVariables.size()]; 746 for (int i = 0; i < all.length; i++) { 747 all[i] = new HeapOperand<Object>((HeapVariable<Object>) vars.next()); 748 all[i].setInstruction(s); 749 // record that all[i] is def'ed in b 750 all[i].getHeapVariable().registerDef(b); 751 } 752 // record that s uses and defs all heap variables 753 uses.put(s, all); 754 defs.put(s, all); 755 // record that instruction s can exit the procedure 756 exits.add(s); 757 } 758 759 /** 760 * Record the heap variables that instruction s defines and uses. 761 * 762 * @param s the instruction in question 763 * @param b the basic block containing s 764 */ 765 void registerInstruction(Instruction s, BasicBlock b) { 766 if (!s.isImplicitLoad() && 767 !s.isImplicitStore() && 768 !s.isAllocation() && 769 s.operator() != PHI && 770 !(insertPEIDeps && 771 (s.isPEI() || 772 Label.conforms(s) || 773 BBend.conforms(s) || 774 s.getOpcode() == UNINT_BEGIN_opcode || 775 s.getOpcode() == UNINT_END_opcode))) { 776 return; 777 } 778 // handled by registerUnknown 779 if (s.isDynamicLinkingPoint()) { 780 return; 781 } 782 switch (s.getOpcode()) { 783 case LABEL_opcode: // only reached if insertPEIDeps 784 labelHelper(s, b); 785 break; 786 case BBEND_opcode: // only reached if insertPEIDeps 787 bbendHelper(s, b); 788 break; 789 case UNINT_BEGIN_opcode: // only reached if insertPEIDeps 790 case UNINT_END_opcode: // only reached if insertPEIDeps 791 registerUse(s, exceptionState); 792 registerDef(s, b, exceptionState); 793 break; 794 case GETFIELD_opcode: 795 getFieldHelper(s, b); 796 break; 797 case PUTFIELD_opcode: 798 putFieldHelper(s, b); 799 break; 800 case GETSTATIC_opcode: 801 getStaticHelper(s, b); 802 break; 803 case PUTSTATIC_opcode: 804 putStaticHelper(s, b); 805 break; 806 case NEW_opcode: 807 case NEW_UNRESOLVED_opcode: 808 newHelper(s, b); 809 break; 810 case NEWARRAY_opcode: 811 case NEWARRAY_UNRESOLVED_opcode: 812 newArrayHelper(s, b); 813 break; 814 case NEWOBJMULTIARRAY_opcode: 815 /* SJF: after talking with Martin, I'm not sure what the 816 correct Array SSA representation for an allocation should 817 be. Since we do not yet use these heap variables, do 818 nothing for now. 819 Future: this should probably def the heap variable for every 820 field of the object type allocated. 821 // treat this opcode like a CALL 822 registerUnknown(s,b); 823 */ 824 break; 825 case INT_ALOAD_opcode: 826 case LONG_ALOAD_opcode: 827 case FLOAT_ALOAD_opcode: 828 case DOUBLE_ALOAD_opcode: 829 case REF_ALOAD_opcode: 830 case BYTE_ALOAD_opcode: 831 case UBYTE_ALOAD_opcode: 832 case USHORT_ALOAD_opcode: 833 case SHORT_ALOAD_opcode: 834 aloadHelper(s, b); 835 break; 836 case INT_ASTORE_opcode: 837 case LONG_ASTORE_opcode: 838 case FLOAT_ASTORE_opcode: 839 case DOUBLE_ASTORE_opcode: 840 case REF_ASTORE_opcode: 841 case BYTE_ASTORE_opcode: 842 case SHORT_ASTORE_opcode: 843 astoreHelper(s, b); 844 break; 845 case ARRAYLENGTH_opcode: 846 arraylengthHelper(s, b); 847 break; 848 case CALL_opcode: 849 case SYSCALL_opcode: 850 case MONITORENTER_opcode: 851 case MONITOREXIT_opcode: 852 case PREPARE_INT_opcode: 853 case PREPARE_ADDR_opcode: 854 case ATTEMPT_INT_opcode: 855 case ATTEMPT_ADDR_opcode: 856 case READ_CEILING_opcode: 857 case WRITE_FLOOR_opcode: 858 // do nothing: these cases handled by registerUnknown 859 break; 860 case UBYTE_LOAD_opcode: 861 case BYTE_LOAD_opcode: 862 case USHORT_LOAD_opcode: 863 case SHORT_LOAD_opcode: 864 case INT_LOAD_opcode: 865 case LONG_LOAD_opcode: 866 case DOUBLE_LOAD_opcode: 867 case REF_LOAD_opcode: 868 // !!TODO: how to handle this special case? 869 break; 870 case BYTE_STORE_opcode: 871 case SHORT_STORE_opcode: 872 case REF_STORE_opcode: 873 case INT_STORE_opcode: 874 case LONG_STORE_opcode: 875 case DOUBLE_STORE_opcode: 876 // !!TODO: how to handle this special case? 877 break; 878 case PHI_opcode: 879 phiHelper(s, b); 880 break; 881 default: 882 if (!isHandledByRegisterUnknown(s.getOpcode()) && !s.isPEI()) { 883 System.out.println("SSA dictionary failed on " + s.toString()); 884 throw new OperationNotImplementedException("SSADictionary: Unsupported opcode " + s); 885 } 886 } // switch 887 if (insertPEIDeps) { 888 if (s.isImplicitStore()) addExceptionStateToUses(s); 889 if (s.isPEI()) addExceptionStateToDefs(s, b); 890 } 891 } 892 893 private boolean isHandledByRegisterUnknown(char opcode) { 894 if (VM.BuildForIA32) { 895 return opcode == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.PREFETCH_opcode; 896 } else { 897 if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); 898 switch (opcode) { 899 case org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBST_opcode: 900 case org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBT_opcode: 901 case org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBTST_opcode: 902 case org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBZ_opcode: 903 case org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBZL_opcode: 904 case org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.ICBI_opcode: 905 return true; 906 default: 907 return false; 908 } 909 } 910 } 911 912 /** 913 * Record the effects of a getfield instruction on the heap array 914 * SSA form. Register the heap variables that this instruction uses and 915 * defs. Note that if inserting uphi functions, a getfield defs a new 916 * heap variable name. 917 * 918 * @param s the getfield instruction 919 * @param b the basic block containing s 920 */ 921 private void getFieldHelper(Instruction s, BasicBlock b) { 922 LocationOperand locOp = GetField.getLocation(s); 923 FieldReference field = locOp.getFieldRef(); 924 registerUse(s, field); 925 if (uphi) { 926 registerDef(s, b, field); 927 } 928 } 929 930 /** 931 * Record the effects of a putfield instruction on the heap array 932 * SSA form. Register the heap variables that this instruction uses and 933 * defs. 934 * 935 * @param s the getfield instruction 936 * @param b the basic block containing s 937 */ 938 private void putFieldHelper(Instruction s, BasicBlock b) { 939 LocationOperand locOp = PutField.getLocation(s); 940 FieldReference field = locOp.getFieldRef(); 941 registerUse(s, field); 942 registerDef(s, b, field); 943 } 944 945 /** 946 * Record the effects of a getstatic instruction on the heap array 947 * SSA form. Register the heap variables that this instruction uses and 948 * defs. Note that if inserting uphi functions, a getstatic defs a new 949 * heap variable name. 950 * 951 * @param s the getstatic instruction 952 * @param b the basic block containing s 953 */ 954 private void getStaticHelper(Instruction s, BasicBlock b) { 955 LocationOperand locOp = GetStatic.getLocation(s); 956 FieldReference field = locOp.getFieldRef(); 957 registerUse(s, field); 958 if (uphi) { 959 registerDef(s, b, field); 960 } 961 } 962 963 /** 964 * Record the effects of a putstatic instruction on the heap array 965 * SSA form. Register the heap variables that this instruction uses and 966 * defs. 967 * 968 * @param s the putstatic instruction 969 * @param b the basic block containing s 970 */ 971 private void putStaticHelper(Instruction s, BasicBlock b) { 972 LocationOperand locOp = PutStatic.getLocation(s); 973 FieldReference field = locOp.getFieldRef(); 974 registerUse(s, field); 975 registerDef(s, b, field); 976 } 977 978 /** 979 * Update the heap array SSA form for an allocation instruction 980 * 981 * @param s the allocation instruction 982 * @param b the basic block containing the allocation 983 */ 984 private void newHelper(Instruction s, BasicBlock b) { 985 /* SJF: after talking with Martin, I'm not sure what the 986 correct Array SSA representation for an allocation should 987 be. Since we do not yet use these heap variables, do 988 nothing for now. 989 Future: this should probably def the heap variable for every 990 field of the object type allocated. 991 TypeOperand typeOp = New.getType(s); 992 RVMType type = typeOp.type; 993 registerUse(s,type); 994 registerDef(s,b,type); 995 */ 996 } 997 998 /** 999 * Update the heap array SSA form for an array allocation instruction 1000 * 1001 * @param s the allocation instruction 1002 * @param b the basic block containing the allocation 1003 */ 1004 private void newArrayHelper(Instruction s, BasicBlock b) { 1005 // TODO: use some class hierarchy analysis 1006 /* SJF: after talking with Martin, I'm not sure what the 1007 correct Array SSA representation for an allocation should 1008 be. Since we do not yet use these heap variables, do 1009 nothing for now. 1010 Future: this should probably def the heap variable for every 1011 field of the object type allocated. 1012 TypeOperand typeOp = NewArray.getType(s); 1013 RVMType type = typeOp.type; 1014 if (!type.asArray().getElementType().isPrimitiveType()) 1015 type = ClassLoaderProxy.JavaLangObjectArrayType; 1016 registerUse(s,type); 1017 registerDef(s,b,type); 1018 */ 1019 } 1020 1021 /** 1022 * Record the effects of a aload instruction on the heap array 1023 * SSA form. Register the heap variables that this instruction uses and 1024 * defs. Note that if inserting uphi functions, a aload defs a new 1025 * heap variable name. 1026 * 1027 * @param s the aload instruction 1028 * @param b the basic block containing s 1029 */ 1030 private void aloadHelper(Instruction s, BasicBlock b) { 1031 // TODO: use some class hierarchy analysis 1032 TypeReference type = ALoad.getArray(s).getType(); 1033 1034 // After cond branch splitting, operand may be a Null constant 1035 // filter out it now -- Feng 1036 if (type.isArrayType()) { 1037 if (!type.getArrayElementType().isPrimitiveType()) { 1038 type = TypeReference.JavaLangObjectArray; 1039 } 1040 registerUse(s, type); 1041 if (uphi) { 1042 registerDef(s, b, type); 1043 } 1044 } 1045 } 1046 1047 /** 1048 * Record the effects of an astore instruction on the heap array 1049 * SSA form. Register the heap variables that this instruction uses and 1050 * defs. 1051 * 1052 * @param s the astore instruction 1053 * @param b the basic block containing s 1054 */ 1055 private void astoreHelper(Instruction s, BasicBlock b) { 1056 // TODO: use some class hierarchy analysis 1057 TypeReference type = AStore.getArray(s).getType(); 1058 1059 // After cond branch splitting, operand may be a Null constant 1060 // filter out it now -- Feng 1061 if (type.isArrayType()) { 1062 if (!type.getArrayElementType().isPrimitiveType()) { 1063 type = TypeReference.JavaLangObjectArray; 1064 } 1065 registerUse(s, type); 1066 registerDef(s, b, type); 1067 } 1068 } 1069 1070 /** 1071 * Record the effects of an arraylength instruction on the heap array 1072 * SSA form. Register the heap variable that this instruction uses. 1073 * 1074 * @param s the arraylength instruction 1075 * @param b the basic block containing s 1076 */ 1077 private void arraylengthHelper(Instruction s, BasicBlock b) { 1078 // TODO: use some class hierarchy analysis 1079 TypeReference type = GuardedUnary.getVal(s).getType(); 1080 1081 // After cond branch splitting, operand may be a Null constant 1082 // filter it out now -- Feng 1083 if (type.isArrayType()) { 1084 if (!type.getArrayElementType().isPrimitiveType()) { 1085 type = TypeReference.JavaLangObjectArray; 1086 } 1087 registerUse(s, type); 1088 } 1089 } 1090 1091 /** 1092 * Record the effects of a phi instruction on the heap array 1093 * SSA form. Register the heap variables that this instruction uses 1094 * and defs. 1095 * 1096 * @param s the phi instruction 1097 * @param b the basic block containing s 1098 */ 1099 private void phiHelper(Instruction s, BasicBlock b) { 1100 // for phi function, we dont' register implicit defs and uses 1101 // since they're explicit in the instruction 1102 /* 1103 Object result = Phi.getResult(s); 1104 if (!(result instanceof HeapOperand)) 1105 return; 1106 HeapOperand H = (HeapOperand)Phi.getResult(s); 1107 Object Htype = H.getHeapType(); 1108 if (Htype instanceof RVMType) { 1109 RVMType t = (RVMType)Htype; 1110 registerDef(s, b, t); 1111 } 1112 else if (Htype instanceof RVMField) { 1113 RVMField f = (RVMField)Htype; 1114 registerDef(s, b, f); 1115 } 1116 else { 1117 String a = (String)Htype; 1118 registerDef(s, b, a); 1119 } 1120 for (int i = 0; i < Phi.getNumberOfValues(s); i++) { 1121 HeapOperand U = (HeapOperand)Phi.getValue(s, i); 1122 Object Utype = U.getHeapType(); 1123 if (Utype instanceof RVMType) { 1124 RVMType t = (RVMType)Utype; 1125 registerUse(s, t); 1126 } 1127 else if (Utype instanceof RVMField) { 1128 RVMField f = (RVMField)Utype; 1129 registerUse(s, f); 1130 } else { 1131 String a = (String)Utype; 1132 registerUse(s, a); 1133 } 1134 } 1135 */ 1136 } 1137 1138 /** 1139 * Record the effects of a label instruction on the heap array 1140 * SSA form. Register the exception state that this instruction defs. 1141 * 1142 * @param s the label instruction 1143 * @param b the basic block containing s 1144 */ 1145 private void labelHelper(Instruction s, BasicBlock b) { 1146 Enumeration<BasicBlock> e = b.getIn(); 1147 boolean newHandler = !e.hasMoreElements(); 1148 while (!newHandler && e.hasMoreElements()) { 1149 if (!(e.nextElement().isExceptionHandlerEquivalent(b))) newHandler = true; 1150 } 1151 if (newHandler) registerDef(s, b, exceptionState); 1152 } 1153 1154 /** 1155 * Record the effects of a bbend instruction on the heap array 1156 * SSA form. Register the exception state that this instruction uses. 1157 * 1158 * @param s the label instruction 1159 * @param b the basic block containing s 1160 */ 1161 private void bbendHelper(Instruction s, BasicBlock b) { 1162 Enumeration<BasicBlock> e = b.getOut(); 1163 boolean newHandler = !e.hasMoreElements(); 1164 while (!newHandler && e.hasMoreElements()) { 1165 if (!(e.nextElement().isExceptionHandlerEquivalent(b))) newHandler = true; 1166 } 1167 if (newHandler) registerUse(s, exceptionState); 1168 } 1169 1170 /** 1171 * Register that an instruction uses a heap variable of a given 1172 * type. 1173 * 1174 * @param s the instruction in question 1175 * @param t the type of the heap variable the instruction uses 1176 */ 1177 private void registerUse(Instruction s, TypeReference t) { 1178 // if the heapTypes set is defined, then we only build Array 1179 // SSA for these types. So, ignore uses of types that are 1180 // not included in the set 1181 if (heapTypes != null) { 1182 if (!heapTypes.contains(t)) { 1183 return; 1184 } 1185 } 1186 HeapVariable<Object> H = findOrCreateHeapVariable(t); 1187 HeapOperand<Object>[] Hprime = new HeapOperand[1]; 1188 Hprime[0] = new HeapOperand<Object>(H); 1189 Hprime[0].setInstruction(s); 1190 uses.put(s, Hprime); 1191 } 1192 1193 /** 1194 * Register that an instruction writes a heap variable for a given 1195 * type. 1196 * 1197 * @param s the instruction in question 1198 * @param b s's basic block 1199 * @param t the type of the heap variable the instruction modifies 1200 */ 1201 private void registerDef(Instruction s, BasicBlock b, TypeReference t) { 1202 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1203 // if the heapTypes set is defined, then we only build Array 1204 // SSA for these types. So, ignore uses of types that are 1205 // not included in the set 1206 if (heapTypes != null) { 1207 if (!heapTypes.contains(t)) { 1208 return; 1209 } 1210 } 1211 HeapVariable<Object> H = findOrCreateHeapVariable(t); 1212 H.registerDef(b); 1213 HeapOperand<Object>[] Hprime = new HeapOperand[1]; 1214 Hprime[0] = new HeapOperand<Object>(H); 1215 Hprime[0].setInstruction(s); 1216 defs.put(s, Hprime); 1217 } 1218 1219 /** 1220 * Register that an instruction uses a heap variable for a given 1221 * field. 1222 * 1223 * @param s the instruction in question 1224 * @param fr the field heap variable the instruction uses 1225 */ 1226 private void registerUse(Instruction s, FieldReference fr) { 1227 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1228 RVMField f = fr.peekResolvedField(); 1229 HeapOperand<Object> H; 1230 if (f == null) { 1231 // can't resolve field at compile time. 1232 // This isn't quite correct, but is somewhat close. 1233 // See defect 3481. 1234 H = new HeapOperand<Object>(findOrCreateHeapVariable(fr)); 1235 } else { 1236 // if the heapTypes set is defined, then we only build Array 1237 // SSA for these types. So, ignore uses of types that are 1238 // not included in the set 1239 if (heapTypes != null) { 1240 if (!heapTypes.contains(f)) { 1241 return; 1242 } 1243 } 1244 H = new HeapOperand<Object>(findOrCreateHeapVariable(f)); 1245 } 1246 HeapOperand<Object>[] Hprime = new HeapOperand[1]; 1247 Hprime[0] = H; 1248 Hprime[0].setInstruction(s); 1249 uses.put(s, Hprime); 1250 } 1251 1252 /** 1253 * Register that instruction <code>s</code> writes a heap variable for 1254 * a given field. 1255 * 1256 * @param s the instruction in question 1257 * @param b <code>s</code>'s basic block 1258 * @param fr the field heap variable the instruction modifies 1259 */ 1260 private void registerDef(Instruction s, BasicBlock b, FieldReference fr) { 1261 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1262 RVMField f = fr.peekResolvedField(); 1263 HeapOperand<Object> H; 1264 if (f == null) { 1265 // can't resolve field at compile time. 1266 // This isn't quite correct, but is somewhat close. 1267 // See bug #1147433 1268 H = new HeapOperand<Object>(findOrCreateHeapVariable(fr)); 1269 } else { 1270 // if the heapTypes set is defined, then we only build Array 1271 // SSA for these types. So, ignore uses of types that are 1272 // not included in the set 1273 if (heapTypes != null) { 1274 if (!heapTypes.contains(f)) { 1275 return; 1276 } 1277 } 1278 H = new HeapOperand<Object>(findOrCreateHeapVariable(f)); 1279 } 1280 H.value.registerDef(b); 1281 HeapOperand<Object>[] Hprime = new HeapOperand[1]; 1282 Hprime[0] = H; 1283 Hprime[0].setInstruction(s); 1284 defs.put(s, Hprime); 1285 } 1286 1287 /** 1288 * Register that an instruction uses a heap variable for a given 1289 * field. 1290 * 1291 * @param s the instruction in question 1292 * @param a the field heap variable the instruction uses 1293 */ 1294 @SuppressWarnings("unchecked") 1295 private void registerUse(Instruction s, String a) { 1296 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1297 // if the heapTypes set is defined, then we only build Array 1298 // SSA for these types. So, ignore uses of types that are 1299 // not included in the set 1300 if (heapTypes != null) { 1301 if (!heapTypes.contains(a)) { 1302 return; 1303 } 1304 } 1305 HeapVariable<Object> H = findOrCreateHeapVariable(a); 1306 HeapOperand<Object>[] Hprime = new HeapOperand[1]; 1307 Hprime[0] = new HeapOperand<Object>(H); 1308 Hprime[0].setInstruction(s); 1309 uses.put(s, Hprime); 1310 } 1311 1312 /** 1313 * Register that the instruction <code>s</code> writes a heap variable for 1314 * a given field. 1315 * 1316 * @param s the instruction in question 1317 * @param b <code>s</code>'s basic block 1318 * @param a XXX TODO Check this XXX The field in question. 1319 */ 1320 @SuppressWarnings("unchecked") 1321 private void registerDef(Instruction s, BasicBlock b, String a) { 1322 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1323 // if the heapTypes set is defined, then we only build Array 1324 // SSA for these types. So, ignore uses of types that are 1325 // not included in the set 1326 if (heapTypes != null) { 1327 if (!heapTypes.contains(a)) { 1328 return; 1329 } 1330 } 1331 HeapVariable<Object> H = findOrCreateHeapVariable(a); 1332 H.registerDef(b); 1333 HeapOperand<Object>[] Hprime = new HeapOperand[1]; 1334 Hprime[0] = new HeapOperand<Object>(H); 1335 Hprime[0].setInstruction(s); 1336 defs.put(s, Hprime); 1337 } 1338 1339 /** 1340 * Returns a copy of H with an additional free slot at position 0 1341 * 1342 * @param H the array of HeapOperands to be extended. 1343 * @return an array with the same contents as the given array and an 1344 * additional free slot at 0. If the array is null, an empty array 1345 * with length 1 will be returned. 1346 */ 1347 @SuppressWarnings("unchecked") 1348 private static HeapOperand<Object>[] extendHArray(HeapOperand<Object>[] H) { 1349 HeapOperand<Object>[] res; 1350 1351 if (H == null) { 1352 res = new HeapOperand[1]; 1353 } else { 1354 res = new HeapOperand[H.length + 1]; 1355 for (int i = 0; i < H.length; ++i) { 1356 res[i + 1] = H[i]; 1357 } 1358 } 1359 return res; 1360 } 1361 1362 /** 1363 * Register that an instruction defines the exception state. 1364 * 1365 * @param s the instruction in question 1366 * @param b s's basic block 1367 */ 1368 @SuppressWarnings("unchecked") 1369 void addExceptionStateToDefs(Instruction s, BasicBlock b) { 1370 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1371 HeapVariable<Object> H = findOrCreateHeapVariable(exceptionState); 1372 H.registerDef(b); 1373 HeapOperand<Object>[] Hprime = extendHArray(defs.get(s)); 1374 Hprime[0] = new HeapOperand<Object>(H); 1375 Hprime[0].setInstruction(s); 1376 defs.put(s, Hprime); 1377 } 1378 1379 /** 1380 * Register that an instruction defines the exception state. 1381 * 1382 * @param s the instruction in question 1383 */ 1384 @SuppressWarnings("unchecked") 1385 void addExceptionStateToUses(Instruction s) { 1386 if (VM.VerifyAssertions) VM._assert(s.operator() != PHI); 1387 HeapVariable<Object> H = findOrCreateHeapVariable(exceptionState); 1388 HeapOperand<Object>[] Hprime = extendHArray(uses.get(s)); 1389 Hprime[0] = new HeapOperand<Object>(H); 1390 Hprime[0].setInstruction(s); 1391 uses.put(s, Hprime); 1392 } 1393 1394 /** 1395 * Return the heap variable for a given type or field with 1396 * number 0. 1397 * If no heap variable yet exits for this type or field, create a new 1398 * one. 1399 * 1400 * @param type the <code> TypeReference </code> or <code> RVMField </code> 1401 * identifying the desired heap variable 1402 * @return the desired heap variable 1403 */ 1404 @SuppressWarnings("unchecked") 1405 private HeapVariable<Object> findOrCreateHeapVariable(Object type) { 1406 if (DEBUG) { 1407 System.out.print("findOrCreateHeapVariable " + type); 1408 } 1409 HeapKey<Object> key = new HeapKey<Object>(0, type); 1410 HeapVariable<Object> H = heapVariables.get(key); 1411 if (DEBUG) { 1412 System.out.println("... found " + H); 1413 } 1414 if (H == null) { 1415 // note: if not found, then we have never created a heap 1416 // variable with the correct type. So, create one, with number 1417 // 0 1418 int number = getNextHeapVariableNumber(type); // should return 0 1419 H = new HeapVariable<Object>(type, number, ir); 1420 heapVariables.put(key, H); 1421 if (DEBUG) { 1422 System.out.println("... created " + heapVariables.get(key)); 1423 } 1424 } 1425 return H; 1426 } 1427 1428 /** 1429 * Get the next number to be assigned to a new heap variable 1430 * for a given type or field. 1431 * 1432 * @param type the <code> TypeReference </code> or <code> RVMField </code> 1433 * identifying the heap variable 1434 * @return the next integer (monotonically increasing) to identify a new 1435 * name for this heap variable 1436 */ 1437 private int getNextHeapVariableNumber(Object type) { 1438 Integer current = nextNumber.get(type); 1439 if (current == null) { 1440 // no number found. Create one. 1441 Integer one = 1; 1442 nextNumber.put(type, one); 1443 return 0; 1444 } 1445 // bump up the number 1446 Integer next = current + 1; 1447 nextNumber.put(type, next); 1448 return current; 1449 } 1450 1451 /** 1452 * Create a phi-function instruction for a heap variable 1453 * 1454 * @param H a symbolic variable for a Heap variable 1455 * @param bb the basic block holding the new phi function 1456 * instruction 1457 * @return the instruction <code> H = phi H,H,..,H </code> 1458 */ 1459 private static Instruction makePhiInstruction(HeapVariable<Object> H, BasicBlock bb) { 1460 int n = bb.getNumberOfIn(); 1461 Enumeration<BasicBlock> in = bb.getIn(); 1462 HeapOperand<Object> lhs = new HeapOperand<Object>(H); 1463 Instruction s = Phi.create(PHI, lhs, n); 1464 lhs.setInstruction(s); 1465 for (int i = 0; i < n; i++) { 1466 HeapOperand<Object> op = new HeapOperand<Object>(H); 1467 op.setInstruction(s); 1468 Phi.setValue(s, i, op); 1469 BasicBlock pred = in.nextElement(); 1470 Phi.setPred(s, i, new BasicBlockOperand(pred)); 1471 } 1472 return s; 1473 } 1474 1475 /** 1476 * This class represents the name of a heap variable in the heap array 1477 * SSA form. 1478 */ 1479 private static final class HeapKey<T> { 1480 /** 1481 * The number and type comprise the name of a heap variable in array SSA 1482 * form 1483 */ 1484 private final int number; 1485 /** 1486 * The number and type comprise the name of a heap variable in array SSA 1487 * form 1488 */ 1489 private final T type; 1490 1491 /** 1492 * Create a new name for a heap variable. 1493 * 1494 * @param number the number, a unique integer from SSA renaming 1495 * @param type the type (a <code> RVMField </code> or <code> 1496 * TypeReference </code> 1497 */ 1498 HeapKey(int number, T type) { 1499 this.number = number; 1500 this.type = type; 1501 } 1502 1503 /** 1504 * Test against another key for equality. This function is used to 1505 * retrive items from hashtables. 1506 * 1507 * @param key the object to compare with 1508 * @return {@code true} or {@code false} as appropriate 1509 */ 1510 @Override 1511 public boolean equals(Object key) { 1512 if (!(key instanceof HeapKey)) { 1513 return false; 1514 } 1515 HeapKey<T> k = (HeapKey) key; 1516 return ((type.equals(k.type)) && (number == k.number)); 1517 } 1518 1519 /** 1520 * Return a hash code for this name. 1521 * 1522 * TODO: come up with a better hash function. 1523 * 1524 * @return the hash code 1525 */ 1526 @Override 1527 public int hashCode() { 1528 return type.hashCode() + 8192 * number; 1529 } 1530 } 1531 1532 /** 1533 * This class implements an <code> Enumeration </code> over all 1534 * instructions for a basic block. This enumeration includes 1535 * explicit instructions in the IR and implicit phi instructions 1536 * for heap variables, which are stored only in this lookaside 1537 * structure. 1538 */ 1539 static final class AllInstructionEnumeration implements Enumeration<Instruction> { 1540 /** 1541 * An enumeration of the explicit instructions in the IR for a basic 1542 * block 1543 */ 1544 private final Enumeration<Instruction> explicitInstructions; 1545 1546 /** 1547 * An enumeration of the implicit instructions in the IR for a basic 1548 * block. These instructions appear only in the SSA dictionary 1549 * lookaside structure. 1550 */ 1551 private final Iterator<Instruction> implicitInstructions; 1552 1553 /** 1554 * The label instruction for the basic block 1555 */ 1556 private Instruction labelInstruction; 1557 1558 /** 1559 * Construct an enumeration for all instructions, both implicit and 1560 * explicit in the IR, for a given basic block 1561 * 1562 * @param bb the basic block whose instructions this enumerates 1563 * @param dict the Heap Array SSA information 1564 */ 1565 AllInstructionEnumeration(BasicBlock bb, SSADictionary dict) { 1566 explicitInstructions = bb.forwardInstrEnumerator(); 1567 implicitInstructions = dict.getHeapPhiInstructions(bb); 1568 labelInstruction = explicitInstructions.nextElement(); 1569 } 1570 1571 /** 1572 * Are there more elements in the enumeration? 1573 * 1574 * @return {@code true} or {@code false} 1575 */ 1576 @Override 1577 public boolean hasMoreElements() { 1578 return (implicitInstructions.hasNext() || explicitInstructions.hasMoreElements()); 1579 } 1580 1581 /** 1582 * Get the next instruction in the enumeration 1583 * 1584 * @return the next instruction 1585 */ 1586 @Override 1587 public Instruction nextElement() { 1588 if (labelInstruction != null) { 1589 Instruction temp = labelInstruction; 1590 labelInstruction = null; 1591 return temp; 1592 } 1593 if (implicitInstructions.hasNext()) { 1594 return implicitInstructions.next(); 1595 } 1596 return explicitInstructions.nextElement(); 1597 } 1598 } 1599}