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