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 */ 013 package org.jikesrvm.compilers.opt.escape; 014 015 import static org.jikesrvm.compilers.opt.ir.Operators.MONITORENTER; 016 import static org.jikesrvm.compilers.opt.ir.Operators.MONITOREXIT; 017 import static org.jikesrvm.compilers.opt.ir.Operators.NEWARRAY_opcode; 018 import static org.jikesrvm.compilers.opt.ir.Operators.NEW_opcode; 019 020 import org.jikesrvm.classloader.RVMType; 021 import org.jikesrvm.compilers.opt.DefUse; 022 import org.jikesrvm.compilers.opt.LocalConstantProp; 023 import org.jikesrvm.compilers.opt.LocalCopyProp; 024 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 025 import org.jikesrvm.compilers.opt.OptOptions; 026 import org.jikesrvm.compilers.opt.Simple; 027 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 028 import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement; 029 import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 030 import org.jikesrvm.compilers.opt.ir.Call; 031 import org.jikesrvm.compilers.opt.ir.IR; 032 import org.jikesrvm.compilers.opt.ir.Instruction; 033 import org.jikesrvm.compilers.opt.ir.New; 034 import org.jikesrvm.compilers.opt.ir.NewArray; 035 import org.jikesrvm.compilers.opt.ir.Register; 036 import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 037 import org.jikesrvm.compilers.opt.ir.operand.Operand; 038 import 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 */ 047 public 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(ir, 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 * PRECONDITION: register lists computed and valid 173 */ 174 private static boolean synchronizesOn(IR ir, Register r) { 175 // walk through uses of r 176 for (RegisterOperand use = r.useList; use != null; use = use.getNext()) { 177 Instruction s = use.instruction; 178 if (s.operator == MONITORENTER) { 179 return true; 180 } 181 if (s.operator == MONITOREXIT) { 182 return true; 183 } 184 // check if this instruction invokes a synchronized method on the 185 // object 186 // we must pass the following conditions: 187 // 1. the method is not static 188 // 2. it is actually invoked on the register operand in question 189 // 3. the method is synchronized 190 if (Call.conforms(s)) { 191 MethodOperand mo = Call.getMethod(s); 192 if (!mo.isStatic()) { 193 Operand invokee = Call.getParam(s, 0); 194 if (invokee == use) { 195 if (!mo.hasPreciseTarget()) return true; // if I don't know exactly what is called, assume the worse 196 if (mo.getTarget().isSynchronized()) { 197 return true; 198 } 199 } 200 } 201 } 202 } 203 return false; 204 } 205 206 /** 207 * Generate an object which will perform scalar replacement of 208 * an aggregate allocated by a given instruction 209 * 210 * <p> PRECONDITION: objects returned by this allocation site do NOT escape 211 * the current method 212 * 213 * @param inst the allocation site 214 * @param ir controlling ir 215 * @return an AggregateReplacer specialized to the allocation site, 216 * null if no legal transformation found 217 */ 218 private AggregateReplacer getAggregateReplacer(Instruction inst, IR ir) { 219 OptOptions options = ir.options; 220 RVMType t = null; 221 if (inst.getOpcode() == NEW_opcode) { 222 t = New.getType(inst).getVMType(); 223 } else if (inst.getOpcode() == NEWARRAY_opcode) { 224 t = NewArray.getType(inst).getVMType(); 225 } else { 226 throw new OptimizingCompilerException("Logic Error in EscapeTransformations"); 227 } 228 229 // first attempt to perform scalar replacement for an object 230 if (t.isClassType() && options.ESCAPE_SCALAR_REPLACE_AGGREGATES) { 231 return ObjectReplacer.getReplacer(inst, ir); 232 } 233 // attempt to perform scalar replacement on a short array 234 if (t.isArrayType() && options.ESCAPE_SCALAR_REPLACE_AGGREGATES) { 235 return ShortArrayReplacer.getReplacer(inst, ir); 236 } 237 return null; 238 } 239 }