001/* 002 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir; 024 025import java.lang.reflect.*; 026import java.util.*; 027 028import jdk.internal.jvmci.code.*; 029import jdk.internal.jvmci.common.*; 030import jdk.internal.jvmci.meta.*; 031 032import com.oracle.graal.compiler.common.*; 033import com.oracle.graal.lir.LIRInstruction.OperandFlag; 034import com.oracle.graal.lir.LIRInstruction.OperandMode; 035 036public class LIRInstructionClass<T> extends LIRIntrospection<T> { 037 038 public static final <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T> c) { 039 return new LIRInstructionClass<>(c); 040 } 041 042 private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class; 043 private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class; 044 045 private final Values uses; 046 private final Values alives; 047 private final Values temps; 048 private final Values defs; 049 private final Fields states; 050 051 private String opcodeConstant; 052 private int opcodeIndex; 053 054 private LIRInstructionClass(Class<T> clazz) { 055 this(clazz, new FieldsScanner.DefaultCalcOffset()); 056 } 057 058 public LIRInstructionClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) { 059 super(clazz); 060 assert INSTRUCTION_CLASS.isAssignableFrom(clazz); 061 062 LIRInstructionFieldsScanner ifs = new LIRInstructionFieldsScanner(calcOffset); 063 ifs.scan(clazz); 064 065 uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class)); 066 alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class)); 067 temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class)); 068 defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class)); 069 070 states = new Fields(ifs.states); 071 data = new Fields(ifs.data); 072 073 opcodeConstant = ifs.opcodeConstant; 074 if (ifs.opcodeField == null) { 075 opcodeIndex = -1; 076 } else { 077 opcodeIndex = ifs.data.indexOf(ifs.opcodeField); 078 } 079 } 080 081 @SuppressWarnings("unchecked") 082 public static <T> LIRInstructionClass<T> get(Class<T> clazz) { 083 try { 084 Field field = clazz.getDeclaredField("TYPE"); 085 field.setAccessible(true); 086 return (LIRInstructionClass<T>) field.get(null); 087 } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { 088 throw new RuntimeException(e); 089 } 090 } 091 092 private static class LIRInstructionFieldsScanner extends LIRFieldsScanner { 093 094 private String opcodeConstant; 095 096 /** 097 * Field (if any) annotated by {@link Opcode}. 098 */ 099 private FieldsScanner.FieldInfo opcodeField; 100 101 public LIRInstructionFieldsScanner(FieldsScanner.CalcOffset calc) { 102 super(calc); 103 104 valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); 105 valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); 106 valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); 107 valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); 108 } 109 110 @Override 111 protected EnumSet<OperandFlag> getFlags(Field field) { 112 EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class); 113 // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so 114 // we have to duplicate the code for every operand mode. 115 // Unfortunately, annotations cannot have an EnumSet property, so we have to convert 116 // from arrays to EnumSet manually. 117 if (field.isAnnotationPresent(LIRInstruction.Use.class)) { 118 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value())); 119 } else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) { 120 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value())); 121 } else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) { 122 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Temp.class).value())); 123 } else if (field.isAnnotationPresent(LIRInstruction.Def.class)) { 124 result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Def.class).value())); 125 } else { 126 JVMCIError.shouldNotReachHere(); 127 } 128 return result; 129 } 130 131 public void scan(Class<?> clazz) { 132 if (clazz.getAnnotation(Opcode.class) != null) { 133 opcodeConstant = clazz.getAnnotation(Opcode.class).value(); 134 } 135 opcodeField = null; 136 137 super.scan(clazz, LIRInstruction.class, false); 138 139 if (opcodeConstant == null && opcodeField == null) { 140 opcodeConstant = clazz.getSimpleName(); 141 if (opcodeConstant.endsWith("Op")) { 142 opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2); 143 } 144 } 145 } 146 147 @Override 148 protected void scanField(Field field, long offset) { 149 Class<?> type = field.getType(); 150 if (STATE_CLASS.isAssignableFrom(type)) { 151 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; 152 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field; 153 states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass())); 154 } else { 155 super.scanField(field, offset); 156 } 157 158 if (field.getAnnotation(Opcode.class) != null) { 159 assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type; 160 assert data.get(data.size() - 1).offset == offset; 161 opcodeField = data.get(data.size() - 1); 162 } 163 } 164 } 165 166 @Override 167 public Fields[] getAllFields() { 168 assert values == null; 169 return new Fields[]{data, uses, alives, temps, defs, states}; 170 } 171 172 @Override 173 public String toString() { 174 StringBuilder str = new StringBuilder(); 175 str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use["); 176 uses.appendFields(str); 177 str.append("] alive["); 178 alives.appendFields(str); 179 str.append("] temp["); 180 temps.appendFields(str); 181 str.append("] def["); 182 defs.appendFields(str); 183 str.append("] state["); 184 states.appendFields(str); 185 str.append("] data["); 186 data.appendFields(str); 187 str.append("]"); 188 return str.toString(); 189 } 190 191 Values getValues(OperandMode mode) { 192 switch (mode) { 193 case USE: 194 return uses; 195 case ALIVE: 196 return alives; 197 case TEMP: 198 return temps; 199 case DEF: 200 return defs; 201 default: 202 throw JVMCIError.shouldNotReachHere("unknown OperandMode: " + mode); 203 } 204 } 205 206 final String getOpcode(LIRInstruction obj) { 207 if (opcodeConstant != null) { 208 return opcodeConstant; 209 } 210 assert opcodeIndex != -1; 211 return String.valueOf(data.getObject(obj, opcodeIndex)); 212 } 213 214 final boolean hasOperands() { 215 return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0; 216 } 217 218 final boolean hasState(LIRInstruction obj) { 219 for (int i = 0; i < states.getCount(); i++) { 220 if (states.getObject(obj, i) != null) { 221 return true; 222 } 223 } 224 return false; 225 } 226 227 final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) { 228 forEach(obj, uses, OperandMode.USE, proc); 229 } 230 231 final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) { 232 forEach(obj, alives, OperandMode.ALIVE, proc); 233 } 234 235 final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) { 236 forEach(obj, temps, OperandMode.TEMP, proc); 237 } 238 239 final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) { 240 forEach(obj, defs, OperandMode.DEF, proc); 241 } 242 243 final void forEachUse(LIRInstruction obj, InstructionValueConsumer proc) { 244 forEach(obj, uses, OperandMode.USE, proc); 245 } 246 247 final void forEachAlive(LIRInstruction obj, InstructionValueConsumer proc) { 248 forEach(obj, alives, OperandMode.ALIVE, proc); 249 } 250 251 final void forEachTemp(LIRInstruction obj, InstructionValueConsumer proc) { 252 forEach(obj, temps, OperandMode.TEMP, proc); 253 } 254 255 final void forEachDef(LIRInstruction obj, InstructionValueConsumer proc) { 256 forEach(obj, defs, OperandMode.DEF, proc); 257 } 258 259 final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) { 260 for (int i = 0; i < states.getCount(); i++) { 261 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 262 if (state != null) { 263 state.forEachState(obj, proc); 264 } 265 } 266 } 267 268 final void forEachState(LIRInstruction obj, InstructionValueConsumer proc) { 269 for (int i = 0; i < states.getCount(); i++) { 270 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 271 if (state != null) { 272 state.forEachState(obj, proc); 273 } 274 } 275 } 276 277 final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) { 278 for (int i = 0; i < states.getCount(); i++) { 279 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 280 if (state != null) { 281 proc.doState(obj, state); 282 } 283 } 284 } 285 286 final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) { 287 Values hints; 288 if (mode == OperandMode.USE) { 289 hints = defs; 290 } else if (mode == OperandMode.DEF) { 291 hints = uses; 292 } else { 293 return null; 294 } 295 296 for (int i = 0; i < hints.getCount(); i++) { 297 if (i < hints.getDirectCount()) { 298 Value hintValue = hints.getValue(obj, i); 299 Value result = proc.doValue(obj, hintValue, null, null); 300 if (result != null) { 301 return result; 302 } 303 } else { 304 Value[] hintValues = hints.getValueArray(obj, i); 305 for (int j = 0; j < hintValues.length; j++) { 306 Value hintValue = hintValues[j]; 307 Value result = proc.doValue(obj, hintValue, null, null); 308 if (result != null) { 309 return result; 310 } 311 } 312 } 313 } 314 return null; 315 } 316 317 String toString(LIRInstruction obj) { 318 StringBuilder result = new StringBuilder(); 319 320 appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs); 321 result.append(String.valueOf(getOpcode(obj)).toUpperCase()); 322 appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives); 323 appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps); 324 325 for (int i = 0; i < data.getCount(); i++) { 326 if (i == opcodeIndex) { 327 continue; 328 } 329 result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data)); 330 } 331 332 for (int i = 0; i < states.getCount(); i++) { 333 LIRFrameState state = (LIRFrameState) states.getObject(obj, i); 334 if (state != null) { 335 result.append(" ").append(states.getName(i)).append(" [bci:"); 336 String sep = ""; 337 for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) { 338 result.append(sep).append(cur.getBCI()); 339 sep = ", "; 340 } 341 result.append("]"); 342 } 343 } 344 345 return result.toString(); 346 } 347}