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 }