1 /* 2 * Copyright (c) 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 package org.graalvm.compiler.lir; 24 25 import java.lang.reflect.Field; 26 import java.util.Arrays; 27 import java.util.EnumSet; 28 29 import org.graalvm.compiler.core.common.FieldIntrospection; 30 import org.graalvm.compiler.core.common.Fields; 31 import org.graalvm.compiler.core.common.FieldsScanner; 32 import org.graalvm.compiler.debug.GraalError; 33 import org.graalvm.compiler.lir.CompositeValue.Component; 34 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 35 import org.graalvm.compiler.lir.LIRIntrospection.LIRFieldsScanner; 36 import org.graalvm.compiler.lir.LIRIntrospection.OperandModeAnnotation; 37 import org.graalvm.compiler.lir.LIRIntrospection.Values; 38 39 /** 40 * Lazily associated metadata for every {@link CompositeValue} type. The metadata includes: 41 * <ul> 42 * <li>The offsets of fields annotated with {@link Component} as well as methods for iterating over 43 * such fields.</li> 44 * </ul> 45 */ 46 public final class CompositeValueClass<T> extends FieldIntrospection<T> { 47 48 /** 49 * The CompositeValueClass is only used for formatting for the most part so cache it as a 50 * ClassValue. 51 */ 52 private static final ClassValue<CompositeValueClass<?>> compositeClass = new ClassValue<CompositeValueClass<?>>() { 53 54 @Override 55 protected CompositeValueClass<?> computeValue(Class<?> type) { 56 CompositeValueClass<?> compositeValueClass = new CompositeValueClass<>(type); 57 assert compositeValueClass.values.getDirectCount() == compositeValueClass.values.getCount() : "only direct fields are allowed in composites"; 58 return compositeValueClass; 59 } 60 61 }; 62 63 @SuppressWarnings("unchecked") 64 public static <T> CompositeValueClass<T> get(Class<T> type) { 65 return (CompositeValueClass<T>) compositeClass.get(type); 66 } 67 68 private final Values values; 69 70 private CompositeValueClass(Class<T> clazz) { 71 super(clazz); 72 73 CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset()); 74 vfs.scan(clazz, CompositeValue.class, false); 75 76 values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class)); 77 data = new Fields(vfs.data); 78 } 79 80 private static class CompositeValueFieldsScanner extends LIRFieldsScanner { 81 82 CompositeValueFieldsScanner(FieldsScanner.CalcOffset calc) { 83 super(calc); 84 valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation()); 85 } 86 87 @Override 88 protected EnumSet<OperandFlag> getFlags(Field field) { 89 EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class); 90 if (field.isAnnotationPresent(CompositeValue.Component.class)) { 91 result.addAll(Arrays.asList(field.getAnnotation(CompositeValue.Component.class).value())); 92 } else { 93 GraalError.shouldNotReachHere(); 94 } 95 return result; 96 } 97 } 98 99 @Override 100 public Fields[] getAllFields() { 101 return new Fields[]{data, values}; 102 } 103 104 @Override 105 public String toString() { 106 StringBuilder str = new StringBuilder(); 107 str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components["); 108 values.appendFields(str); 109 str.append("] data["); 110 data.appendFields(str); 111 str.append("]"); 112 return str.toString(); 113 } 114 115 public static String format(CompositeValue obj) { 116 CompositeValueClass<?> valueClass = compositeClass.get(obj.getClass()); 117 StringBuilder result = new StringBuilder(); 118 119 LIRIntrospection.appendValues(result, obj, "", "", "{", "}", new String[]{""}, valueClass.values); 120 121 for (int i = 0; i < valueClass.data.getCount(); i++) { 122 result.append(" ").append(valueClass.data.getName(i)).append(": ").append(LIRIntrospection.getFieldString(obj, i, valueClass.data)); 123 } 124 125 return result.toString(); 126 } 127 }