1 /* 2 * Copyright (c) 2012, 2015, 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 static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; 26 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 27 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 28 29 import java.lang.annotation.Annotation; 30 import java.lang.reflect.Field; 31 import java.lang.reflect.Modifier; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.EnumSet; 35 import java.util.HashMap; 36 import java.util.Map; 37 import java.util.Map.Entry; 38 39 import org.graalvm.compiler.core.common.FieldIntrospection; 40 import org.graalvm.compiler.core.common.Fields; 41 import org.graalvm.compiler.core.common.FieldsScanner; 42 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 43 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 44 45 import jdk.vm.ci.code.RegisterValue; 46 import jdk.vm.ci.code.StackSlot; 47 import jdk.vm.ci.meta.Value; 48 49 abstract class LIRIntrospection<T> extends FieldIntrospection<T> { 50 51 private static final Class<Value> VALUE_CLASS = Value.class; 52 private static final Class<ConstantValue> CONSTANT_VALUE_CLASS = ConstantValue.class; 53 private static final Class<Variable> VARIABLE_CLASS = Variable.class; 54 private static final Class<RegisterValue> REGISTER_VALUE_CLASS = RegisterValue.class; 55 private static final Class<StackSlot> STACK_SLOT_CLASS = StackSlot.class; 56 private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class; 57 58 LIRIntrospection(Class<T> clazz) { 59 super(clazz); 60 } 61 62 protected static class Values extends Fields { 63 private final int directCount; 64 private final EnumSet<OperandFlag>[] flags; 65 66 public Values(OperandModeAnnotation mode) { 67 this(mode.directCount, mode.values); 68 } 69 70 @SuppressWarnings({"unchecked"}) 71 public Values(int directCount, ArrayList<ValueFieldInfo> fields) { 72 super(fields); 73 this.directCount = directCount; 74 flags = (EnumSet<OperandFlag>[]) new EnumSet<?>[fields.size()]; 75 for (int i = 0; i < fields.size(); i++) { 76 flags[i] = fields.get(i).flags; 77 } 78 } 79 80 public int getDirectCount() { 81 return directCount; 82 } 83 84 public EnumSet<OperandFlag> getFlags(int i) { 85 return flags[i]; 86 } 87 88 protected Value getValue(Object obj, int index) { 89 return (Value) getObject(obj, index); 90 } 91 92 protected void setValue(Object obj, int index, Value value) { 93 putObject(obj, index, value); 94 } 95 96 protected Value[] getValueArray(Object obj, int index) { 97 return (Value[]) getObject(obj, index); 98 } 99 100 protected void setValueArray(Object obj, int index, Value[] valueArray) { 101 putObject(obj, index, valueArray); 102 } 103 } 104 105 /** 106 * The component values in an {@link LIRInstruction} or {@link CompositeValue}. 107 */ 108 protected Values values; 109 110 protected static class ValueFieldInfo extends FieldsScanner.FieldInfo { 111 112 final EnumSet<OperandFlag> flags; 113 114 public ValueFieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass, EnumSet<OperandFlag> flags) { 115 super(offset, name, type, declaringClass); 116 assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type); 117 this.flags = flags; 118 } 119 120 /** 121 * Sorts non-array fields before array fields. 122 */ 123 @Override 124 public int compareTo(FieldsScanner.FieldInfo o) { 125 if (VALUE_ARRAY_CLASS.isAssignableFrom(o.type)) { 126 if (!VALUE_ARRAY_CLASS.isAssignableFrom(type)) { 127 return -1; 128 } 129 } else { 130 if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { 131 return 1; 132 } 133 } 134 return super.compareTo(o); 135 } 136 137 @Override 138 public String toString() { 139 return super.toString() + flags; 140 } 141 } 142 143 protected static class OperandModeAnnotation { 144 145 /** 146 * Number of non-array fields in {@link #values}. 147 */ 148 public int directCount; 149 public final ArrayList<ValueFieldInfo> values = new ArrayList<>(); 150 } 151 152 protected abstract static class LIRFieldsScanner extends FieldsScanner { 153 154 public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations; 155 public final ArrayList<FieldsScanner.FieldInfo> states = new ArrayList<>(); 156 157 public LIRFieldsScanner(FieldsScanner.CalcOffset calc) { 158 super(calc); 159 valueAnnotations = new HashMap<>(); 160 } 161 162 protected OperandModeAnnotation getOperandModeAnnotation(Field field) { 163 OperandModeAnnotation result = null; 164 for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) { 165 Annotation annotation = field.getAnnotation(entry.getKey()); 166 if (annotation != null) { 167 assert result == null : "Field has two operand mode annotations: " + field; 168 result = entry.getValue(); 169 } 170 } 171 return result; 172 } 173 174 protected abstract EnumSet<OperandFlag> getFlags(Field field); 175 176 @Override 177 protected void scanField(Field field, long offset) { 178 Class<?> type = field.getType(); 179 if (VALUE_CLASS.isAssignableFrom(type) && !CONSTANT_VALUE_CLASS.isAssignableFrom(type)) { 180 assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field; 181 OperandModeAnnotation annotation = getOperandModeAnnotation(field); 182 assert annotation != null : "Field must have operand mode annotation: " + field; 183 EnumSet<OperandFlag> flags = getFlags(field); 184 assert verifyFlags(field, type, flags); 185 annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); 186 annotation.directCount++; 187 } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { 188 OperandModeAnnotation annotation = getOperandModeAnnotation(field); 189 assert annotation != null : "Field must have operand mode annotation: " + field; 190 EnumSet<OperandFlag> flags = getFlags(field); 191 assert verifyFlags(field, type.getComponentType(), flags); 192 annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); 193 } else { 194 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; 195 assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field; 196 super.scanField(field, offset); 197 } 198 } 199 200 private static boolean verifyFlags(Field field, Class<?> type, EnumSet<OperandFlag> flags) { 201 if (flags.contains(REG)) { 202 assert type.isAssignableFrom(REGISTER_VALUE_CLASS) || type.isAssignableFrom(VARIABLE_CLASS) : "Cannot assign RegisterValue / Variable to field with REG flag:" + field; 203 } 204 if (flags.contains(STACK)) { 205 assert type.isAssignableFrom(STACK_SLOT_CLASS) : "Cannot assign StackSlot to field with STACK flag:" + field; 206 } 207 if (flags.contains(CONST)) { 208 assert type.isAssignableFrom(CONSTANT_VALUE_CLASS) : "Cannot assign Constant to field with CONST flag:" + field; 209 } 210 return true; 211 } 212 } 213 214 protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedure proc) { 215 for (int i = 0; i < values.getCount(); i++) { 216 assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i)); 217 218 if (i < values.getDirectCount()) { 219 Value value = values.getValue(inst, i); 220 Value newValue; 221 if (value instanceof CompositeValue) { 222 CompositeValue composite = (CompositeValue) value; 223 newValue = composite.forEachComponent(inst, mode, proc); 224 } else { 225 newValue = proc.doValue(inst, value, mode, values.getFlags(i)); 226 } 227 if (!value.identityEquals(newValue)) { 228 values.setValue(inst, i, newValue); 229 } 230 } else { 231 Value[] valueArray = values.getValueArray(inst, i); 232 for (int j = 0; j < valueArray.length; j++) { 233 Value value = valueArray[j]; 234 Value newValue; 235 if (value instanceof CompositeValue) { 236 CompositeValue composite = (CompositeValue) value; 237 newValue = composite.forEachComponent(inst, mode, proc); 238 } else { 239 newValue = proc.doValue(inst, value, mode, values.getFlags(i)); 240 } 241 if (!value.identityEquals(newValue)) { 242 valueArray[j] = newValue; 243 } 244 } 245 } 246 } 247 } 248 249 protected static void visitEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueConsumer proc) { 250 for (int i = 0; i < values.getCount(); i++) { 251 assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i)); 252 253 if (i < values.getDirectCount()) { 254 Value value = values.getValue(inst, i); 255 if (value instanceof CompositeValue) { 256 CompositeValue composite = (CompositeValue) value; 257 composite.visitEachComponent(inst, mode, proc); 258 } else { 259 proc.visitValue(inst, value, mode, values.getFlags(i)); 260 } 261 } else { 262 Value[] valueArray = values.getValueArray(inst, i); 263 for (int j = 0; j < valueArray.length; j++) { 264 Value value = valueArray[j]; 265 if (value instanceof CompositeValue) { 266 CompositeValue composite = (CompositeValue) value; 267 composite.visitEachComponent(inst, mode, proc); 268 } else { 269 proc.visitValue(inst, value, mode, values.getFlags(i)); 270 } 271 } 272 } 273 } 274 } 275 276 protected static void appendValues(StringBuilder sb, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) { 277 int total = 0; 278 for (Fields fields : fieldsList) { 279 total += fields.getCount(); 280 } 281 if (total == 0) { 282 return; 283 } 284 285 sb.append(start); 286 if (total > 1) { 287 sb.append(startMultiple); 288 } 289 String sep = ""; 290 int i = 0; 291 for (Fields fields : fieldsList) { 292 for (int j = 0; j < fields.getCount(); j++) { 293 sb.append(sep).append(prefix[i]); 294 if (total > 1) { 295 sb.append(fields.getName(j)).append(": "); 296 } 297 sb.append(getFieldString(obj, j, fields)); 298 sep = ", "; 299 } 300 i++; 301 } 302 if (total > 1) { 303 sb.append(endMultiple); 304 } 305 sb.append(end); 306 } 307 308 protected static String getFieldString(Object obj, int index, Fields fields) { 309 Object value = fields.get(obj, index); 310 Class<?> type = fields.getType(index); 311 if (value == null || type.isPrimitive() || !type.isArray()) { 312 return String.valueOf(value); 313 } 314 if (type == int[].class) { 315 return Arrays.toString((int[]) value); 316 } else if (type == double[].class) { 317 return Arrays.toString((double[]) value); 318 } else if (type == byte[].class) { 319 byte[] byteValue = (byte[]) value; 320 if (isPrintableAsciiString(byteValue)) { 321 return toString(byteValue); 322 } else { 323 return Arrays.toString(byteValue); 324 } 325 } else if (!type.getComponentType().isPrimitive()) { 326 return Arrays.toString((Object[]) value); 327 } 328 assert false : "unhandled field type: " + type; 329 return ""; 330 } 331 332 /** 333 * Tests if all values in this string are printable ASCII characters or value \0 (b in 334 * [0x20,0x7F]) or b == 0. 335 * 336 * @param array 337 * @return true if there are only printable ASCII characters and \0, false otherwise 338 */ 339 private static boolean isPrintableAsciiString(byte[] array) { 340 for (byte b : array) { 341 char c = (char) b; 342 if (c != 0 && c < 0x20 && c > 0x7F) { 343 return false; 344 } 345 } 346 return true; 347 } 348 349 private static String toString(byte[] bytes) { 350 StringBuilder sb = new StringBuilder(); 351 sb.append('"'); 352 for (byte b : bytes) { 353 if (b == 0) { 354 sb.append("\\0"); 355 } else if (b == '"') { 356 sb.append("\\\""); 357 } else if (b == '\n') { 358 sb.append("\\n"); 359 } else { 360 sb.append((char) b); 361 } 362 } 363 sb.append('"'); 364 return sb.toString(); 365 } 366 }