1 /* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.lir; 24 25 import java.lang.reflect.Field; 26 import java.util.Arrays; 27 import java.util.EnumSet; 28 29 import org.graalvm.compiler.core.common.Fields; 30 import org.graalvm.compiler.core.common.FieldsScanner; 31 import org.graalvm.compiler.debug.GraalError; 32 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 33 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 34 35 import jdk.vm.ci.code.BytecodeFrame; 36 import jdk.vm.ci.meta.Value; 37 38 public class LIRInstructionClass<T> extends LIRIntrospection<T> { 39 40 public static <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T> c) { 41 return new LIRInstructionClass<>(c); 42 } 43 44 private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class; 45 private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class; 46 47 private final Values uses; 48 private final Values alives; 49 private final Values temps; 50 private final Values defs; 51 private final Fields states; 52 53 private String opcodeConstant; 54 private int opcodeIndex; 55 56 private LIRInstructionClass(Class<T> clazz) { 57 this(clazz, new FieldsScanner.DefaultCalcOffset()); 58 } 59 60 public LIRInstructionClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) { 61 super(clazz); 62 assert INSTRUCTION_CLASS.isAssignableFrom(clazz); 63 64 LIRInstructionFieldsScanner ifs = new LIRInstructionFieldsScanner(calcOffset); 65 ifs.scan(clazz); 66 67 uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class)); 68 alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class)); 69 temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class)); 70 defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class)); 71 72 states = new Fields(ifs.states); 73 data = new Fields(ifs.data); 74 75 opcodeConstant = ifs.opcodeConstant; 76 if (ifs.opcodeField == null) { 77 opcodeIndex = -1; 78 } else { 79 opcodeIndex = ifs.data.indexOf(ifs.opcodeField); 80 } 81 } 82 83 @SuppressWarnings("unchecked") 84 public static <T> LIRInstructionClass<T> get(Class<T> clazz) { 85 try { 86 Field field = clazz.getDeclaredField("TYPE"); 87 field.setAccessible(true); 88 return (LIRInstructionClass<T>) field.get(null); 89 } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { 90 throw new RuntimeException(e); 91 } 92 } 93 94 private static class LIRInstructionFieldsScanner extends LIRFieldsScanner { 95 96 private String opcodeConstant; 97 98 /** 99 * Field (if any) annotated by {@link Opcode}. 100 */ 101 private FieldsScanner.FieldInfo opcodeField; 102 103 LIRInstructionFieldsScanner(FieldsScanner.CalcOffset calc) { 104 super(calc); 105 106 valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); 107 valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); 108 valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); 109 valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); 110 } 111 112 @Override 113 protected EnumSet<OperandFlag> getFlags(Field field) { 114 EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class); 115 // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so 116 // we have to duplicate the code for every operand mode. 117 // Unfortunately, annotations cannot have an EnumSet property, so we have to convert 118 // from arrays to EnumSet manually. 119 if (field.isAnnotationPresent(LIRInstruction.Use.class)) { 120 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value())); 121 } else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) { 122 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value())); 123 } else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) { 124 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Temp.class).value())); 125 } else if (field.isAnnotationPresent(LIRInstruction.Def.class)) { 126 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Def.class).value())); 127 } else { 128 GraalError.shouldNotReachHere(); 129 } 130 return result; 131 } 132 133 public void scan(Class<?> clazz) { 134 if (clazz.getAnnotation(Opcode.class) != null) { 135 opcodeConstant = clazz.getAnnotation(Opcode.class).value(); 136 } 137 opcodeField = null; 138 139 super.scan(clazz, LIRInstruction.class, false); 140 141 if (opcodeConstant == null && opcodeField == null) { 142 opcodeConstant = clazz.getSimpleName(); 143 if (opcodeConstant.endsWith("Op")) { 144 opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2); 145 } 146 } 147 } 148 149 @Override 150 protected void scanField(Field field, long offset) { 151 Class<?> type = field.getType(); 152 if (STATE_CLASS.isAssignableFrom(type)) { 153 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; 154 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field; 155 states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass())); 156 } else { 157 super.scanField(field, offset); 158 } 159 160 if (field.getAnnotation(Opcode.class) != null) { 161 assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type; 162 assert data.get(data.size() - 1).offset == offset; 163 opcodeField = data.get(data.size() - 1); 164 } 165 } 166 } 167 168 @Override 169 public Fields[] getAllFields() { 170 assert values == null; 171 return new Fields[]{data, uses, alives, temps, defs, states}; 172 } 173 174 @Override 175 public String toString() { 176 StringBuilder str = new StringBuilder(); 177 str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use["); 178 uses.appendFields(str); 179 str.append("] alive["); 180 alives.appendFields(str); 181 str.append("] temp["); 182 temps.appendFields(str); 183 str.append("] def["); 184 defs.appendFields(str); 185 str.append("] state["); 186 states.appendFields(str); 187 str.append("] data["); 188 data.appendFields(str); 189 str.append("]"); 190 return str.toString(); 191 } 192 193 Values getValues(OperandMode mode) { 194 switch (mode) { 195 case USE: 196 return uses; 197 case ALIVE: 198 return alives; 199 case TEMP: 200 return temps; 201 case DEF: 202 return defs; 203 default: 204 throw GraalError.shouldNotReachHere("unknown OperandMode: " + mode); 205 } 206 } 207 208 final String getOpcode(LIRInstruction obj) { 209 if (opcodeConstant != null) { 210 return opcodeConstant; 211 } 212 assert opcodeIndex != -1; 213 return String.valueOf(data.getObject(obj, opcodeIndex)); 214 } 215 216 final boolean hasOperands() { 217 return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0; 218 } 219 220 final boolean hasState(LIRInstruction obj) { 221 for (int i = 0; i < states.getCount(); i++) { 222 if (states.getObject(obj, i) != null) { 223 return true; 224 } 225 } 226 return false; 227 } 228 229 final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) { 230 forEach(obj, uses, OperandMode.USE, proc); 231 } 232 233 final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) { 234 forEach(obj, alives, OperandMode.ALIVE, proc); 235 } 236 237 final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) { 238 forEach(obj, temps, OperandMode.TEMP, proc); 239 } 240 241 final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) { 242 forEach(obj, defs, OperandMode.DEF, proc); 243 } 244 245 final void visitEachUse(LIRInstruction obj, InstructionValueConsumer proc) { 246 visitEach(obj, uses, OperandMode.USE, proc); 247 } 248 249 final void visitEachAlive(LIRInstruction obj, InstructionValueConsumer proc) { 250 visitEach(obj, alives, OperandMode.ALIVE, proc); 251 } 252 253 final void visitEachTemp(LIRInstruction obj, InstructionValueConsumer proc) { 254 visitEach(obj, temps, OperandMode.TEMP, proc); 255 } 256 257 final void visitEachDef(LIRInstruction obj, InstructionValueConsumer proc) { 258 visitEach(obj, defs, OperandMode.DEF, proc); 259 } 260 261 final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) { 262 for (int i = 0; i < states.getCount(); i++) { 263 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 264 if (state != null) { 265 state.forEachState(obj, proc); 266 } 267 } 268 } 269 270 final void visitEachState(LIRInstruction obj, InstructionValueConsumer proc) { 271 for (int i = 0; i < states.getCount(); i++) { 272 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 273 if (state != null) { 274 state.visitEachState(obj, proc); 275 } 276 } 277 } 278 279 final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) { 280 for (int i = 0; i < states.getCount(); i++) { 281 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 282 if (state != null) { 283 proc.doState(obj, state); 284 } 285 } 286 } 287 288 final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) { 289 Values hints; 290 if (mode == OperandMode.USE) { 291 hints = defs; 292 } else if (mode == OperandMode.DEF) { 293 hints = uses; 294 } else { 295 return null; 296 } 297 298 for (int i = 0; i < hints.getCount(); i++) { 299 if (i < hints.getDirectCount()) { 300 Value hintValue = hints.getValue(obj, i); 301 Value result = proc.doValue(obj, hintValue, null, null); 302 if (result != null) { 303 return result; 304 } 305 } else { 306 Value[] hintValues = hints.getValueArray(obj, i); 307 for (int j = 0; j < hintValues.length; j++) { 308 Value hintValue = hintValues[j]; 309 Value result = proc.doValue(obj, hintValue, null, null); 310 if (result != null) { 311 return result; 312 } 313 } 314 } 315 } 316 return null; 317 } 318 319 String toString(LIRInstruction obj) { 320 StringBuilder result = new StringBuilder(); 321 322 appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs); 323 result.append(String.valueOf(getOpcode(obj)).toUpperCase()); 324 appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives); 325 appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps); 326 327 for (int i = 0; i < data.getCount(); i++) { 328 if (i == opcodeIndex) { 329 continue; 330 } 331 result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data)); 332 } 333 334 for (int i = 0; i < states.getCount(); i++) { 335 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 336 if (state != null) { 337 result.append(" ").append(states.getName(i)).append(" [bci:"); 338 String sep = ""; 339 for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) { 340 result.append(sep).append(cur.getBCI()); 341 sep = ", "; 342 } 343 result.append("]"); 344 } 345 } 346 347 return result.toString(); 348 } 349 }