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.escape; 014 015import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER; 016import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT; 017import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_opcode; 018import static org.jikesrvm.compilers.opt.ir.Operators.NEW_opcode; 019 020import org.jikesrvm.classloader.RVMType; 021import org.jikesrvm.compilers.opt.DefUse; 022import org.jikesrvm.compilers.opt.LocalConstantProp; 023import org.jikesrvm.compilers.opt.LocalCopyProp; 024import org.jikesrvm.compilers.opt.OptimizingCompilerException; 025import org.jikesrvm.compilers.opt.OptOptions; 026import org.jikesrvm.compilers.opt.Simple; 027import org.jikesrvm.compilers.opt.driver.CompilerPhase; 028import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement; 029import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 030import org.jikesrvm.compilers.opt.ir.Call; 031import org.jikesrvm.compilers.opt.ir.IR; 032import org.jikesrvm.compilers.opt.ir.Instruction; 033import org.jikesrvm.compilers.opt.ir.New; 034import org.jikesrvm.compilers.opt.ir.NewArray; 035import org.jikesrvm.compilers.opt.ir.Register; 036import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 037import org.jikesrvm.compilers.opt.ir.operand.Operand; 038import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 039 040/** 041 * Transformations that use escape analysis. 042 * <ul> 043 * <li> 1. synchronization removal 044 * <li> 2. scalar replacement of aggregates and short arrays 045 * </ul> 046 */ 047public class EscapeTransformations extends CompilerPhase { 048 049 /** 050 * Transforms to clean the IR prior to another round of escape transformations 051 */ 052 private static final OptimizationPlanElement escapeCleanUp = 053 OptimizationPlanCompositeElement.compose("Clean up escape transformations", 054 new Object[]{new LocalCopyProp(), 055 new LocalConstantProp(), 056 new Simple(0, true, false, false, false)}); 057 058 /** 059 * Return this instance of this phase. This phase contains no 060 * per-compilation instance fields. 061 * @param ir not used 062 * @return this 063 */ 064 @Override 065 public CompilerPhase newExecution(IR ir) { 066 return this; 067 } 068 069 @Override 070 public final boolean shouldPerform(OptOptions options) { 071 return options.ESCAPE_MONITOR_REMOVAL || options.ESCAPE_SCALAR_REPLACE_AGGREGATES; 072 } 073 074 @Override 075 public final String getName() { 076 return "Escape Transformations"; 077 } 078 079 @Override 080 public final boolean printingEnabled(OptOptions options, boolean before) { 081 return false; 082 } 083 084 /** 085 * Perform the transformations 086 * 087 * @param ir IR for the target method 088 */ 089 @Override 090 public void perform(IR ir) { 091 // perform simple optimizations to increase efficacy 092 DefUse.computeDU(ir); 093 DefUse.recomputeSSA(ir); 094 SimpleEscape analyzer = new SimpleEscape(); 095 // do multiple passes to catch chains of objects that can be removed 096 boolean removedAggregate; 097 do { 098 removedAggregate = false; 099 FI_EscapeSummary summary = analyzer.simpleEscapeAnalysis(ir); 100 // pass through registers. look for registers that point 101 // to objects that do not escape. When found, 102 // perform the transformations 103 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { 104 // check if register is SSA 105 if (!reg.isSSA()) { 106 continue; 107 } 108 // The following can occur for guards. Why? 109 if (reg.defList == null) { 110 continue; 111 } 112 // ********************************************************* 113 // check if def is allocation. If so, try scalar replacement 114 // of aggregates 115 // ********************************************************* 116 Instruction def = reg.defList.instruction; 117 if (ir.options.ESCAPE_SCALAR_REPLACE_AGGREGATES && summary.isMethodLocal(reg)) { 118 AggregateReplacer s = null; 119 if ((def.getOpcode() == NEW_opcode) || (def.getOpcode() == NEWARRAY_opcode)) { 120 s = getAggregateReplacer(def, ir); 121 } 122 if (s != null) { 123 // org.jikesrvm.VM.sysWrite("Scalar replacing "+def+" in "+ir.method+"\n"); 124 s.transform(); 125 removedAggregate = true; 126 } 127 } 128 // ********************************************************* 129 // Now remove synchronizations 130 // ********************************************************* 131 if (ir.options.ESCAPE_MONITOR_REMOVAL && summary.isThreadLocal(reg)) { 132 UnsyncReplacer unsync = null; 133 if ((def.getOpcode() == NEW_opcode) || (def.getOpcode() == NEWARRAY_opcode)) { 134 unsync = getUnsyncReplacer(reg, def, ir); 135 } 136 if (unsync != null) { 137 // VM.sysWrite("Removing synchronization on "+def+" in "+ir.method+"\n"); 138 unsync.transform(); 139 } 140 } 141 } 142 if (removedAggregate) { 143 // do quick clean up of IR 144 // org.jikesrvm.VM.sysWrite("Cleaning up IR in "+ir.method+"\n"); 145 escapeCleanUp.perform(ir); 146 } 147 } while (removedAggregate); 148 } 149 150 /** 151 * Generate an object which transforms defs & uses of "synchronized" 152 * objects to defs & uses of "unsynchronized" objects 153 * 154 * <p> PRECONDITION: objects pointed to by reg do NOT escape 155 * 156 * @param reg the pointer whose defs and uses should be transformed 157 * @param inst the allocation site 158 * @param ir controlling ir 159 * @return an UnsyncReplacer specialized to the allocation site, 160 * null if no legal transformation found 161 */ 162 private UnsyncReplacer getUnsyncReplacer(Register reg, Instruction inst, IR ir) { 163 if (!synchronizesOn(reg)) { 164 return null; 165 } 166 return UnsyncReplacer.getReplacer(inst, ir); 167 } 168 169 /** 170 * Is there an instruction in this IR which causes synchronization 171 * on an object pointed to by a particular register? 172 * 173 * PRECONDITION: register lists computed and valid 174 * @param r the object's register 175 * @return whether synchronization occurs on the given object 176 */ 177 private static boolean synchronizesOn(Register r) { 178 // walk through uses of r 179 for (RegisterOperand use = r.useList; use != null; use = use.getNext()) { 180 Instruction s = use.instruction; 181 if (s.operator() == MONITORENTER) { 182 return true; 183 } 184 if (s.operator() == MONITOREXIT) { 185 return true; 186 } 187 // check if this instruction invokes a synchronized method on the 188 // object 189 // we must pass the following conditions: 190 // 1. the method is not static 191 // 2. it is actually invoked on the register operand in question 192 // 3. the method is synchronized 193 if (Call.conforms(s)) { 194 MethodOperand mo = Call.getMethod(s); 195 if (!mo.isStatic()) { 196 Operand invokee = Call.getParam(s, 0); 197 if (invokee == use) { 198 if (!mo.hasPreciseTarget()) return true; // if I don't know exactly what is called, assume the worse 199 if (mo.getTarget().isSynchronized()) { 200 return true; 201 } 202 } 203 } 204 } 205 } 206 return false; 207 } 208 209 /** 210 * Generate an object which will perform scalar replacement of 211 * an aggregate allocated by a given instruction 212 * 213 * <p> PRECONDITION: objects returned by this allocation site do NOT escape 214 * the current method 215 * 216 * @param inst the allocation site 217 * @param ir controlling ir 218 * @return an AggregateReplacer specialized to the allocation site, 219 * null if no legal transformation found 220 */ 221 private AggregateReplacer getAggregateReplacer(Instruction inst, IR ir) { 222 OptOptions options = ir.options; 223 RVMType t = null; 224 if (inst.getOpcode() == NEW_opcode) { 225 t = New.getType(inst).getVMType(); 226 } else if (inst.getOpcode() == NEWARRAY_opcode) { 227 t = NewArray.getType(inst).getVMType(); 228 } else { 229 throw new OptimizingCompilerException("Logic Error in EscapeTransformations"); 230 } 231 232 // first attempt to perform scalar replacement for an object 233 if (t.isClassType() && options.ESCAPE_SCALAR_REPLACE_AGGREGATES) { 234 return ObjectReplacer.getReplacer(inst, ir); 235 } 236 // attempt to perform scalar replacement on a short array 237 if (t.isArrayType() && options.ESCAPE_SCALAR_REPLACE_AGGREGATES) { 238 return ShortArrayReplacer.getReplacer(inst, ir); 239 } 240 return null; 241 } 242}