001/* 002 * Copyright (c) 2012, 2014, 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 static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 026 027import java.lang.annotation.*; 028import java.lang.reflect.*; 029import java.util.*; 030import java.util.Map.Entry; 031 032import jdk.internal.jvmci.code.*; 033import jdk.internal.jvmci.meta.*; 034 035import com.oracle.graal.compiler.common.*; 036import com.oracle.graal.lir.LIRInstruction.OperandFlag; 037import com.oracle.graal.lir.LIRInstruction.OperandMode; 038 039abstract class LIRIntrospection<T> extends FieldIntrospection<T> { 040 041 private static final Class<Value> VALUE_CLASS = Value.class; 042 private static final Class<JavaConstant> CONSTANT_CLASS = JavaConstant.class; 043 private static final Class<Variable> VARIABLE_CLASS = Variable.class; 044 private static final Class<RegisterValue> REGISTER_VALUE_CLASS = RegisterValue.class; 045 private static final Class<StackSlot> STACK_SLOT_CLASS = StackSlot.class; 046 private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class; 047 048 public LIRIntrospection(Class<T> clazz) { 049 super(clazz); 050 } 051 052 protected static class Values extends Fields { 053 private final int directCount; 054 private final EnumSet<OperandFlag>[] flags; 055 056 public Values(OperandModeAnnotation mode) { 057 this(mode.directCount, mode.values); 058 } 059 060 @SuppressWarnings("unchecked") 061 public Values(int directCount, ArrayList<ValueFieldInfo> fields) { 062 super(fields); 063 this.directCount = directCount; 064 flags = new EnumSet[fields.size()]; 065 for (int i = 0; i < fields.size(); i++) { 066 flags[i] = fields.get(i).flags; 067 } 068 } 069 070 public int getDirectCount() { 071 return directCount; 072 } 073 074 public EnumSet<OperandFlag> getFlags(int i) { 075 return flags[i]; 076 } 077 078 protected Value getValue(Object obj, int index) { 079 return (Value) getObject(obj, index); 080 } 081 082 protected void setValue(Object obj, int index, Value value) { 083 putObject(obj, index, value); 084 } 085 086 protected Value[] getValueArray(Object obj, int index) { 087 return (Value[]) getObject(obj, index); 088 } 089 090 protected void setValueArray(Object obj, int index, Value[] valueArray) { 091 putObject(obj, index, valueArray); 092 } 093 } 094 095 /** 096 * The component values in an {@link LIRInstruction} or {@link CompositeValue}. 097 */ 098 protected Values values; 099 100 protected static class ValueFieldInfo extends FieldsScanner.FieldInfo { 101 102 final EnumSet<OperandFlag> flags; 103 104 public ValueFieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass, EnumSet<OperandFlag> flags) { 105 super(offset, name, type, declaringClass); 106 assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type); 107 this.flags = flags; 108 } 109 110 /** 111 * Sorts non-array fields before array fields. 112 */ 113 @Override 114 public int compareTo(FieldsScanner.FieldInfo o) { 115 if (VALUE_ARRAY_CLASS.isAssignableFrom(o.type)) { 116 if (!VALUE_ARRAY_CLASS.isAssignableFrom(type)) { 117 return -1; 118 } 119 } else { 120 if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { 121 return 1; 122 } 123 } 124 return super.compareTo(o); 125 } 126 127 @Override 128 public String toString() { 129 return super.toString() + flags; 130 } 131 } 132 133 protected static class OperandModeAnnotation { 134 135 /** 136 * Number of non-array fields in {@link #values}. 137 */ 138 public int directCount; 139 public final ArrayList<ValueFieldInfo> values = new ArrayList<>(); 140 } 141 142 protected abstract static class LIRFieldsScanner extends FieldsScanner { 143 144 public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations; 145 public final ArrayList<FieldsScanner.FieldInfo> states = new ArrayList<>(); 146 147 public LIRFieldsScanner(FieldsScanner.CalcOffset calc) { 148 super(calc); 149 valueAnnotations = new HashMap<>(); 150 } 151 152 protected OperandModeAnnotation getOperandModeAnnotation(Field field) { 153 OperandModeAnnotation result = null; 154 for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) { 155 Annotation annotation = field.getAnnotation(entry.getKey()); 156 if (annotation != null) { 157 assert result == null : "Field has two operand mode annotations: " + field; 158 result = entry.getValue(); 159 } 160 } 161 return result; 162 } 163 164 protected abstract EnumSet<OperandFlag> getFlags(Field field); 165 166 @Override 167 protected void scanField(Field field, long offset) { 168 Class<?> type = field.getType(); 169 if (VALUE_CLASS.isAssignableFrom(type) && !CONSTANT_CLASS.isAssignableFrom(type)) { 170 assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field; 171 OperandModeAnnotation annotation = getOperandModeAnnotation(field); 172 assert annotation != null : "Field must have operand mode annotation: " + field; 173 EnumSet<OperandFlag> flags = getFlags(field); 174 assert verifyFlags(field, type, flags); 175 annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); 176 annotation.directCount++; 177 } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { 178 OperandModeAnnotation annotation = getOperandModeAnnotation(field); 179 assert annotation != null : "Field must have operand mode annotation: " + field; 180 EnumSet<OperandFlag> flags = getFlags(field); 181 assert verifyFlags(field, type.getComponentType(), flags); 182 annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); 183 } else { 184 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; 185 assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field; 186 super.scanField(field, offset); 187 } 188 } 189 190 private static boolean verifyFlags(Field field, Class<?> type, EnumSet<OperandFlag> flags) { 191 if (flags.contains(REG)) { 192 assert type.isAssignableFrom(REGISTER_VALUE_CLASS) || type.isAssignableFrom(VARIABLE_CLASS) : "Cannot assign RegisterValue / Variable to field with REG flag:" + field; 193 } 194 if (flags.contains(STACK)) { 195 assert type.isAssignableFrom(STACK_SLOT_CLASS) : "Cannot assign StackSlot to field with STACK flag:" + field; 196 } 197 if (flags.contains(CONST)) { 198 assert type.isAssignableFrom(CONSTANT_CLASS) : "Cannot assign Constant to field with CONST flag:" + field; 199 } 200 return true; 201 } 202 } 203 204 protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedure proc) { 205 for (int i = 0; i < values.getCount(); i++) { 206 assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i)); 207 208 if (i < values.getDirectCount()) { 209 Value value = values.getValue(inst, i); 210 Value newValue; 211 if (value instanceof CompositeValue) { 212 CompositeValue composite = (CompositeValue) value; 213 newValue = composite.forEachComponent(inst, mode, proc); 214 } else { 215 newValue = proc.doValue(inst, value, mode, values.getFlags(i)); 216 } 217 if (!value.identityEquals(newValue)) { 218 values.setValue(inst, i, newValue); 219 } 220 } else { 221 Value[] valueArray = values.getValueArray(inst, i); 222 for (int j = 0; j < valueArray.length; j++) { 223 Value value = valueArray[j]; 224 Value newValue; 225 if (value instanceof CompositeValue) { 226 CompositeValue composite = (CompositeValue) value; 227 newValue = composite.forEachComponent(inst, mode, proc); 228 } else { 229 newValue = proc.doValue(inst, value, mode, values.getFlags(i)); 230 } 231 if (!value.identityEquals(newValue)) { 232 valueArray[j] = newValue; 233 } 234 } 235 } 236 } 237 } 238 239 protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueConsumer proc) { 240 for (int i = 0; i < values.getCount(); i++) { 241 assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i)); 242 243 if (i < values.getDirectCount()) { 244 Value value = values.getValue(inst, i); 245 if (value instanceof CompositeValue) { 246 CompositeValue composite = (CompositeValue) value; 247 composite.forEachComponent(inst, mode, proc); 248 } else { 249 proc.visitValue(inst, value, mode, values.getFlags(i)); 250 } 251 } else { 252 Value[] valueArray = values.getValueArray(inst, i); 253 for (int j = 0; j < valueArray.length; j++) { 254 Value value = valueArray[j]; 255 if (value instanceof CompositeValue) { 256 CompositeValue composite = (CompositeValue) value; 257 composite.forEachComponent(inst, mode, proc); 258 } else { 259 proc.visitValue(inst, value, mode, values.getFlags(i)); 260 } 261 } 262 } 263 } 264 } 265 266 protected static void appendValues(StringBuilder sb, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) { 267 int total = 0; 268 for (Fields fields : fieldsList) { 269 total += fields.getCount(); 270 } 271 if (total == 0) { 272 return; 273 } 274 275 sb.append(start); 276 if (total > 1) { 277 sb.append(startMultiple); 278 } 279 String sep = ""; 280 int i = 0; 281 for (Fields fields : fieldsList) { 282 for (int j = 0; j < fields.getCount(); j++) { 283 sb.append(sep).append(prefix[i]); 284 if (total > 1) { 285 sb.append(fields.getName(j)).append(": "); 286 } 287 sb.append(getFieldString(obj, j, fields)); 288 sep = ", "; 289 } 290 i++; 291 } 292 if (total > 1) { 293 sb.append(endMultiple); 294 } 295 sb.append(end); 296 } 297 298 protected static String getFieldString(Object obj, int index, Fields fields) { 299 Object value = fields.get(obj, index); 300 Class<?> type = fields.getType(index); 301 if (value == null || type.isPrimitive() || !type.isArray()) { 302 return String.valueOf(value); 303 } 304 if (type == int[].class) { 305 return Arrays.toString((int[]) value); 306 } else if (type == double[].class) { 307 return Arrays.toString((double[]) value); 308 } else if (type == byte[].class) { 309 byte[] byteValue = (byte[]) value; 310 if (isPrintableAsciiString(byteValue)) { 311 return toString(byteValue); 312 } else { 313 return Arrays.toString(byteValue); 314 } 315 } else if (!type.getComponentType().isPrimitive()) { 316 return Arrays.toString((Object[]) value); 317 } 318 assert false : "unhandled field type: " + type; 319 return ""; 320 } 321 322 /** 323 * Tests if all values in this string are printable ASCII characters or value \0 (b in 324 * [0x20,0x7F]) or b == 0. 325 * 326 * @param array 327 * @return true if there are only printable ASCII characters and \0, false otherwise 328 */ 329 private static boolean isPrintableAsciiString(byte[] array) { 330 for (byte b : array) { 331 char c = (char) b; 332 if (c != 0 && c < 0x20 && c > 0x7F) { 333 return false; 334 } 335 } 336 return true; 337 } 338 339 private static String toString(byte[] bytes) { 340 StringBuilder sb = new StringBuilder(); 341 sb.append('"'); 342 for (byte b : bytes) { 343 if (b == 0) { 344 sb.append("\\0"); 345 } else if (b == '"') { 346 sb.append("\\\""); 347 } else if (b == '\n') { 348 sb.append("\\n"); 349 } else { 350 sb.append((char) b); 351 } 352 } 353 sb.append('"'); 354 return sb.toString(); 355 } 356}