001/*
002 * Copyright (c) 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.common.*;
029
030import com.oracle.graal.compiler.common.*;
031import com.oracle.graal.lir.CompositeValue.Component;
032import com.oracle.graal.lir.LIRInstruction.OperandFlag;
033import com.oracle.graal.lir.LIRIntrospection.LIRFieldsScanner;
034import com.oracle.graal.lir.LIRIntrospection.OperandModeAnnotation;
035import com.oracle.graal.lir.LIRIntrospection.Values;
036
037/**
038 * Lazily associated metadata for every {@link CompositeValue} type. The metadata includes:
039 * <ul>
040 * <li>The offsets of fields annotated with {@link Component} as well as methods for iterating over
041 * such fields.</li>
042 * </ul>
043 */
044public final class CompositeValueClass<T> extends FieldIntrospection<T> {
045
046    /**
047     * The CompositeValueClass is only used for formatting for the most part so cache it as a
048     * ClassValue.
049     */
050    private static final ClassValue<CompositeValueClass<?>> compositeClass = new ClassValue<CompositeValueClass<?>>() {
051
052        @Override
053        protected CompositeValueClass<?> computeValue(Class<?> type) {
054            CompositeValueClass<?> compositeValueClass = new CompositeValueClass<>(type);
055            assert compositeValueClass.values.getDirectCount() == compositeValueClass.values.getCount() : "only direct fields are allowed in composites";
056            return compositeValueClass;
057        }
058
059    };
060
061    @SuppressWarnings("unchecked")
062    public static <T> CompositeValueClass<T> get(Class<T> type) {
063        return (CompositeValueClass<T>) compositeClass.get(type);
064    }
065
066    private final Values values;
067
068    private CompositeValueClass(Class<T> clazz) {
069        super(clazz);
070
071        CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset());
072        vfs.scan(clazz, CompositeValue.class, false);
073
074        values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class));
075        data = new Fields(vfs.data);
076    }
077
078    private static class CompositeValueFieldsScanner extends LIRFieldsScanner {
079
080        public CompositeValueFieldsScanner(FieldsScanner.CalcOffset calc) {
081            super(calc);
082            valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
083        }
084
085        @Override
086        protected EnumSet<OperandFlag> getFlags(Field field) {
087            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
088            if (field.isAnnotationPresent(CompositeValue.Component.class)) {
089                result.addAll(Arrays.asList(field.getAnnotation(CompositeValue.Component.class).value()));
090            } else {
091                JVMCIError.shouldNotReachHere();
092            }
093            return result;
094        }
095    }
096
097    @Override
098    public Fields[] getAllFields() {
099        return new Fields[]{data, values};
100    }
101
102    @Override
103    public String toString() {
104        StringBuilder str = new StringBuilder();
105        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
106        values.appendFields(str);
107        str.append("] data[");
108        data.appendFields(str);
109        str.append("]");
110        return str.toString();
111    }
112
113    public static String format(CompositeValue obj) {
114        CompositeValueClass<?> valueClass = compositeClass.get(obj.getClass());
115        StringBuilder result = new StringBuilder();
116
117        LIRIntrospection.appendValues(result, obj, "", "", "{", "}", new String[]{""}, valueClass.values);
118
119        for (int i = 0; i < valueClass.data.getCount(); i++) {
120            result.append(" ").append(valueClass.data.getName(i)).append(": ").append(LIRIntrospection.getFieldString(obj, i, valueClass.data));
121        }
122
123        return result.toString();
124    }
125}