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 */ 23package org.graalvm.compiler.lir; 24 25import java.lang.reflect.Field; 26import java.util.Arrays; 27import java.util.EnumSet; 28 29import org.graalvm.compiler.core.common.Fields; 30import org.graalvm.compiler.core.common.FieldsScanner; 31import org.graalvm.compiler.debug.GraalError; 32import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 33import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 34import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; 35import org.graalvm.compiler.lir.StandardOp.MoveOp; 36import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; 37 38import jdk.vm.ci.code.BytecodeFrame; 39import jdk.vm.ci.meta.Value; 40 41public class LIRInstructionClass<T> extends LIRIntrospection<T> { 42 43 public static <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T> c) { 44 return new LIRInstructionClass<>(c); 45 } 46 47 private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class; 48 private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class; 49 50 private final Values uses; 51 private final Values alives; 52 private final Values temps; 53 private final Values defs; 54 private final Fields states; 55 56 private final boolean isMoveOp; 57 private final boolean isValueMoveOp; 58 private final boolean isLoadConstantOp; 59 60 private String opcodeConstant; 61 private int opcodeIndex; 62 63 private LIRInstructionClass(Class<T> clazz) { 64 this(clazz, new FieldsScanner.DefaultCalcOffset()); 65 } 66 67 public LIRInstructionClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) { 68 super(clazz); 69 assert INSTRUCTION_CLASS.isAssignableFrom(clazz); 70 71 LIRInstructionFieldsScanner ifs = new LIRInstructionFieldsScanner(calcOffset); 72 ifs.scan(clazz); 73 74 uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class)); 75 alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class)); 76 temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class)); 77 defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class)); 78 79 states = new Fields(ifs.states); 80 data = new Fields(ifs.data); 81 82 opcodeConstant = ifs.opcodeConstant; 83 if (ifs.opcodeField == null) { 84 opcodeIndex = -1; 85 } else { 86 opcodeIndex = ifs.data.indexOf(ifs.opcodeField); 87 } 88 89 isMoveOp = MoveOp.class.isAssignableFrom(clazz); 90 isValueMoveOp = ValueMoveOp.class.isAssignableFrom(clazz); 91 isLoadConstantOp = LoadConstantOp.class.isAssignableFrom(clazz); 92 } 93 94 @SuppressWarnings("unchecked") 95 public static <T> LIRInstructionClass<T> get(Class<T> clazz) { 96 try { 97 Field field = clazz.getDeclaredField("TYPE"); 98 field.setAccessible(true); 99 return (LIRInstructionClass<T>) field.get(null); 100 } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { 101 throw new RuntimeException(e); 102 } 103 } 104 105 private static class LIRInstructionFieldsScanner extends LIRFieldsScanner { 106 107 private String opcodeConstant; 108 109 /** 110 * Field (if any) annotated by {@link Opcode}. 111 */ 112 private FieldsScanner.FieldInfo opcodeField; 113 114 LIRInstructionFieldsScanner(FieldsScanner.CalcOffset calc) { 115 super(calc); 116 117 valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); 118 valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); 119 valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); 120 valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); 121 } 122 123 @Override 124 protected EnumSet<OperandFlag> getFlags(Field field) { 125 EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class); 126 // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so 127 // we have to duplicate the code for every operand mode. 128 // Unfortunately, annotations cannot have an EnumSet property, so we have to convert 129 // from arrays to EnumSet manually. 130 if (field.isAnnotationPresent(LIRInstruction.Use.class)) { 131 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value())); 132 } else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) { 133 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value())); 134 } else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) { 135 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Temp.class).value())); 136 } else if (field.isAnnotationPresent(LIRInstruction.Def.class)) { 137 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Def.class).value())); 138 } else { 139 GraalError.shouldNotReachHere(); 140 } 141 return result; 142 } 143 144 public void scan(Class<?> clazz) { 145 if (clazz.getAnnotation(Opcode.class) != null) { 146 opcodeConstant = clazz.getAnnotation(Opcode.class).value(); 147 } 148 opcodeField = null; 149 150 super.scan(clazz, LIRInstruction.class, false); 151 152 if (opcodeConstant == null && opcodeField == null) { 153 opcodeConstant = clazz.getSimpleName(); 154 if (opcodeConstant.endsWith("Op")) { 155 opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2); 156 } 157 } 158 } 159 160 @Override 161 protected void scanField(Field field, long offset) { 162 Class<?> type = field.getType(); 163 if (STATE_CLASS.isAssignableFrom(type)) { 164 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; 165 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field; 166 states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass())); 167 } else { 168 super.scanField(field, offset); 169 } 170 171 if (field.getAnnotation(Opcode.class) != null) { 172 assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type; 173 assert data.get(data.size() - 1).offset == offset; 174 opcodeField = data.get(data.size() - 1); 175 } 176 } 177 } 178 179 @Override 180 public Fields[] getAllFields() { 181 assert values == null; 182 return new Fields[]{data, uses, alives, temps, defs, states}; 183 } 184 185 @Override 186 public String toString() { 187 StringBuilder str = new StringBuilder(); 188 str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use["); 189 uses.appendFields(str); 190 str.append("] alive["); 191 alives.appendFields(str); 192 str.append("] temp["); 193 temps.appendFields(str); 194 str.append("] def["); 195 defs.appendFields(str); 196 str.append("] state["); 197 states.appendFields(str); 198 str.append("] data["); 199 data.appendFields(str); 200 str.append("]"); 201 return str.toString(); 202 } 203 204 Values getValues(OperandMode mode) { 205 switch (mode) { 206 case USE: 207 return uses; 208 case ALIVE: 209 return alives; 210 case TEMP: 211 return temps; 212 case DEF: 213 return defs; 214 default: 215 throw GraalError.shouldNotReachHere("unknown OperandMode: " + mode); 216 } 217 } 218 219 final String getOpcode(LIRInstruction obj) { 220 if (opcodeConstant != null) { 221 return opcodeConstant; 222 } 223 assert opcodeIndex != -1; 224 return String.valueOf(data.getObject(obj, opcodeIndex)); 225 } 226 227 final boolean hasOperands() { 228 return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0; 229 } 230 231 final boolean hasState(LIRInstruction obj) { 232 for (int i = 0; i < states.getCount(); i++) { 233 if (states.getObject(obj, i) != null) { 234 return true; 235 } 236 } 237 return false; 238 } 239 240 final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) { 241 forEach(obj, uses, OperandMode.USE, proc); 242 } 243 244 final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) { 245 forEach(obj, alives, OperandMode.ALIVE, proc); 246 } 247 248 final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) { 249 forEach(obj, temps, OperandMode.TEMP, proc); 250 } 251 252 final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) { 253 forEach(obj, defs, OperandMode.DEF, proc); 254 } 255 256 final void visitEachUse(LIRInstruction obj, InstructionValueConsumer proc) { 257 visitEach(obj, uses, OperandMode.USE, proc); 258 } 259 260 final void visitEachAlive(LIRInstruction obj, InstructionValueConsumer proc) { 261 visitEach(obj, alives, OperandMode.ALIVE, proc); 262 } 263 264 final void visitEachTemp(LIRInstruction obj, InstructionValueConsumer proc) { 265 visitEach(obj, temps, OperandMode.TEMP, proc); 266 } 267 268 final void visitEachDef(LIRInstruction obj, InstructionValueConsumer proc) { 269 visitEach(obj, defs, OperandMode.DEF, proc); 270 } 271 272 final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) { 273 for (int i = 0; i < states.getCount(); i++) { 274 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 275 if (state != null) { 276 state.forEachState(obj, proc); 277 } 278 } 279 } 280 281 final void visitEachState(LIRInstruction obj, InstructionValueConsumer proc) { 282 for (int i = 0; i < states.getCount(); i++) { 283 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 284 if (state != null) { 285 state.visitEachState(obj, proc); 286 } 287 } 288 } 289 290 final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) { 291 for (int i = 0; i < states.getCount(); i++) { 292 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 293 if (state != null) { 294 proc.doState(obj, state); 295 } 296 } 297 } 298 299 final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) { 300 Values hints; 301 if (mode == OperandMode.USE) { 302 hints = defs; 303 } else if (mode == OperandMode.DEF) { 304 hints = uses; 305 } else { 306 return null; 307 } 308 309 for (int i = 0; i < hints.getCount(); i++) { 310 if (i < hints.getDirectCount()) { 311 Value hintValue = hints.getValue(obj, i); 312 Value result = proc.doValue(obj, hintValue, null, null); 313 if (result != null) { 314 return result; 315 } 316 } else { 317 Value[] hintValues = hints.getValueArray(obj, i); 318 for (int j = 0; j < hintValues.length; j++) { 319 Value hintValue = hintValues[j]; 320 Value result = proc.doValue(obj, hintValue, null, null); 321 if (result != null) { 322 return result; 323 } 324 } 325 } 326 } 327 return null; 328 } 329 330 String toString(LIRInstruction obj) { 331 StringBuilder result = new StringBuilder(); 332 333 appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs); 334 result.append(String.valueOf(getOpcode(obj)).toUpperCase()); 335 appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives); 336 appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps); 337 338 for (int i = 0; i < data.getCount(); i++) { 339 if (i == opcodeIndex) { 340 continue; 341 } 342 result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data)); 343 } 344 345 for (int i = 0; i < states.getCount(); i++) { 346 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 347 if (state != null) { 348 result.append(" ").append(states.getName(i)).append(" [bci:"); 349 String sep = ""; 350 for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) { 351 result.append(sep).append(cur.getBCI()); 352 sep = ", "; 353 } 354 result.append("]"); 355 } 356 } 357 358 return result.toString(); 359 } 360 361 final boolean isMoveOp() { 362 return isMoveOp; 363 } 364 365 final boolean isValueMoveOp() { 366 return isValueMoveOp; 367 } 368 369 final boolean isLoadConstantOp() { 370 return isLoadConstantOp; 371 } 372} 373