LIRInstructionClass.java revision 12651:6ef01bd40ce2
1222900Snp/*
2222900Snp * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3222900Snp * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4222900Snp *
5222900Snp * This code is free software; you can redistribute it and/or modify it
6222900Snp * under the terms of the GNU General Public License version 2 only, as
7222900Snp * published by the Free Software Foundation.
8222900Snp *
9222900Snp * This code is distributed in the hope that it will be useful, but WITHOUT
10222900Snp * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11222900Snp * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12222900Snp * version 2 for more details (a copy is included in the LICENSE file that
13222900Snp * accompanied this code).
14222900Snp *
15222900Snp * You should have received a copy of the GNU General Public License version
16222900Snp * 2 along with this work; if not, write to the Free Software Foundation,
17222900Snp * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18222900Snp *
19222900Snp * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20222900Snp * or visit www.oracle.com if you need additional information or have any
21222900Snp * questions.
22222900Snp */
23222900Snppackage org.graalvm.compiler.lir;
24222900Snp
25222900Snpimport java.lang.reflect.Field;
26222900Snpimport java.util.Arrays;
27222900Snpimport java.util.EnumSet;
28222900Snp
29222900Snpimport org.graalvm.compiler.core.common.Fields;
30222900Snpimport org.graalvm.compiler.core.common.FieldsScanner;
31287297Srodrigcimport org.graalvm.compiler.debug.GraalError;
32222900Snpimport org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
33228594Snpimport org.graalvm.compiler.lir.LIRInstruction.OperandMode;
34222900Snp
35228594Snpimport jdk.vm.ci.code.BytecodeFrame;
36287297Srodrigcimport jdk.vm.ci.meta.Value;
37287297Srodrigc
38222900Snppublic class LIRInstructionClass<T> extends LIRIntrospection<T> {
39287297Srodrigc
40222900Snp    public static <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T> c) {
41222900Snp        return new LIRInstructionClass<>(c);
42287297Srodrigc    }
43287297Srodrigc
44287297Srodrigc    private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
45287297Srodrigc    private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;
46287297Srodrigc
47287297Srodrigc    private final Values uses;
48287297Srodrigc    private final Values alives;
49287297Srodrigc    private final Values temps;
50287297Srodrigc    private final Values defs;
51287297Srodrigc    private final Fields states;
52287297Srodrigc
53222900Snp    private String opcodeConstant;
54222900Snp    private int opcodeIndex;
55259048Snp
56222974Snp    private LIRInstructionClass(Class<T> clazz) {
57222974Snp        this(clazz, new FieldsScanner.DefaultCalcOffset());
58222900Snp    }
59253870Snp
60222900Snp    public LIRInstructionClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) {
61222900Snp        super(clazz);
62222900Snp        assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
63222900Snp
64222900Snp        LIRInstructionFieldsScanner ifs = new LIRInstructionFieldsScanner(calcOffset);
65222900Snp        ifs.scan(clazz);
66222900Snp
67222900Snp        uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class));
68222900Snp        alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class));
69222900Snp        temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class));
70222900Snp        defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class));
71222900Snp
72222974Snp        states = new Fields(ifs.states);
73222974Snp        data = new Fields(ifs.data);
74222974Snp
75222974Snp        opcodeConstant = ifs.opcodeConstant;
76222974Snp        if (ifs.opcodeField == null) {
77222974Snp            opcodeIndex = -1;
78222974Snp        } else {
79222974Snp            opcodeIndex = ifs.data.indexOf(ifs.opcodeField);
80222974Snp        }
81222900Snp    }
82296471Snp
83296471Snp    @SuppressWarnings("unchecked")
84222900Snp    public static <T> LIRInstructionClass<T> get(Class<T> clazz) {
85222900Snp        try {
86222900Snp            Field field = clazz.getDeclaredField("TYPE");
87222900Snp            field.setAccessible(true);
88222900Snp            return (LIRInstructionClass<T>) field.get(null);
89222900Snp        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
90222900Snp            throw new RuntimeException(e);
91241416Snp        }
92222974Snp    }
93222900Snp
94222900Snp    private static class LIRInstructionFieldsScanner extends LIRFieldsScanner {
95222900Snp
96222900Snp        private String opcodeConstant;
97241401Snp
98306823Snp        /**
99306823Snp         * Field (if any) annotated by {@link Opcode}.
100228594Snp         */
101228594Snp        private FieldsScanner.FieldInfo opcodeField;
102269106Snp
103222900Snp        LIRInstructionFieldsScanner(FieldsScanner.CalcOffset calc) {
104222900Snp            super(calc);
105222900Snp
106259048Snp            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation());
107259048Snp            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation());
108222900Snp            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation());
109228594Snp            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation());
110259048Snp        }
111253691Snp
112253691Snp        @Override
113222900Snp        protected EnumSet<OperandFlag> getFlags(Field field) {
114222900Snp            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
115222900Snp            // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so
116222900Snp            // we have to duplicate the code for every operand mode.
117222900Snp            // Unfortunately, annotations cannot have an EnumSet property, so we have to convert
118222900Snp            // from arrays to EnumSet manually.
119222900Snp            if (field.isAnnotationPresent(LIRInstruction.Use.class)) {
120222900Snp                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value()));
121222900Snp            } else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) {
122222900Snp                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value()));
123222900Snp            } else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) {
124222900Snp                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Temp.class).value()));
125222900Snp            } else if (field.isAnnotationPresent(LIRInstruction.Def.class)) {
126222900Snp                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Def.class).value()));
127222900Snp            } else {
128222900Snp                GraalError.shouldNotReachHere();
129222900Snp            }
130222900Snp            return result;
131222900Snp        }
132222900Snp
133222900Snp        public void scan(Class<?> clazz) {
134222900Snp            if (clazz.getAnnotation(Opcode.class) != null) {
135222900Snp                opcodeConstant = clazz.getAnnotation(Opcode.class).value();
136222900Snp            }
137253870Snp            opcodeField = null;
138222900Snp
139222900Snp            super.scan(clazz, LIRInstruction.class, false);
140222900Snp
141222900Snp            if (opcodeConstant == null && opcodeField == null) {
142222900Snp                opcodeConstant = clazz.getSimpleName();
143222900Snp                if (opcodeConstant.endsWith("Op")) {
144222900Snp                    opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2);
145222900Snp                }
146222900Snp            }
147222900Snp        }
148222900Snp
149222900Snp        @Override
150222900Snp        protected void scanField(Field field, long offset) {
151222900Snp            Class<?> type = field.getType();
152222900Snp            if (STATE_CLASS.isAssignableFrom(type)) {
153222900Snp                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
154222900Snp                assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
155222900Snp                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass()));
156222900Snp            } else {
157222900Snp                super.scanField(field, offset);
158222900Snp            }
159222900Snp
160222900Snp            if (field.getAnnotation(Opcode.class) != null) {
161222900Snp                assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type;
162222900Snp                assert data.get(data.size() - 1).offset == offset;
163222900Snp                opcodeField = data.get(data.size() - 1);
164222900Snp            }
165222900Snp        }
166222900Snp    }
167222900Snp
168222900Snp    @Override
169222900Snp    public Fields[] getAllFields() {
170222900Snp        assert values == null;
171222900Snp        return new Fields[]{data, uses, alives, temps, defs, states};
172222900Snp    }
173222900Snp
174222900Snp    @Override
175222900Snp    public String toString() {
176222900Snp        StringBuilder str = new StringBuilder();
177222900Snp        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
178222900Snp        uses.appendFields(str);
179222900Snp        str.append("] alive[");
180222900Snp        alives.appendFields(str);
181222900Snp        str.append("] temp[");
182222900Snp        temps.appendFields(str);
183222900Snp        str.append("] def[");
184222900Snp        defs.appendFields(str);
185222900Snp        str.append("] state[");
186222900Snp        states.appendFields(str);
187222900Snp        str.append("] data[");
188222900Snp        data.appendFields(str);
189222900Snp        str.append("]");
190222900Snp        return str.toString();
191222900Snp    }
192222900Snp
193222900Snp    Values getValues(OperandMode mode) {
194222900Snp        switch (mode) {
195222900Snp            case USE:
196222900Snp                return uses;
197222900Snp            case ALIVE:
198222900Snp                return alives;
199222900Snp            case TEMP:
200222900Snp                return temps;
201222900Snp            case DEF:
202222900Snp                return defs;
203222900Snp            default:
204222900Snp                throw GraalError.shouldNotReachHere("unknown OperandMode: " + mode);
205222900Snp        }
206222900Snp    }
207222900Snp
208222900Snp    final String getOpcode(LIRInstruction obj) {
209222900Snp        if (opcodeConstant != null) {
210222900Snp            return opcodeConstant;
211222900Snp        }
212222900Snp        assert opcodeIndex != -1;
213222900Snp        return String.valueOf(data.getObject(obj, opcodeIndex));
214222900Snp    }
215222900Snp
216222900Snp    final boolean hasOperands() {
217222900Snp        return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0;
218222900Snp    }
219222900Snp
220222900Snp    final boolean hasState(LIRInstruction obj) {
221222900Snp        for (int i = 0; i < states.getCount(); i++) {
222222900Snp            if (states.getObject(obj, i) != null) {
223222900Snp                return true;
224222900Snp            }
225222900Snp        }
226222900Snp        return false;
227222900Snp    }
228222900Snp
229222900Snp    final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) {
230222900Snp        forEach(obj, uses, OperandMode.USE, proc);
231222900Snp    }
232222900Snp
233222900Snp    final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) {
234222900Snp        forEach(obj, alives, OperandMode.ALIVE, proc);
235222900Snp    }
236222900Snp
237222900Snp    final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) {
238222900Snp        forEach(obj, temps, OperandMode.TEMP, proc);
239222900Snp    }
240222900Snp
241222900Snp    final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) {
242222900Snp        forEach(obj, defs, OperandMode.DEF, proc);
243222900Snp    }
244222900Snp
245222900Snp    final void visitEachUse(LIRInstruction obj, InstructionValueConsumer proc) {
246222900Snp        visitEach(obj, uses, OperandMode.USE, proc);
247222900Snp    }
248222900Snp
249222900Snp    final void visitEachAlive(LIRInstruction obj, InstructionValueConsumer proc) {
250222900Snp        visitEach(obj, alives, OperandMode.ALIVE, proc);
251222900Snp    }
252222900Snp
253222900Snp    final void visitEachTemp(LIRInstruction obj, InstructionValueConsumer proc) {
254222900Snp        visitEach(obj, temps, OperandMode.TEMP, proc);
255222900Snp    }
256222900Snp
257222900Snp    final void visitEachDef(LIRInstruction obj, InstructionValueConsumer proc) {
258222900Snp        visitEach(obj, defs, OperandMode.DEF, proc);
259222900Snp    }
260222900Snp
261222900Snp    final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) {
262222900Snp        for (int i = 0; i < states.getCount(); i++) {
263222900Snp            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
264222900Snp            if (state != null) {
265222900Snp                state.forEachState(obj, proc);
266222900Snp            }
267222900Snp        }
268222900Snp    }
269222900Snp
270222900Snp    final void visitEachState(LIRInstruction obj, InstructionValueConsumer proc) {
271222900Snp        for (int i = 0; i < states.getCount(); i++) {
272222900Snp            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
273222900Snp            if (state != null) {
274222900Snp                state.visitEachState(obj, proc);
275222900Snp            }
276222900Snp        }
277222900Snp    }
278222900Snp
279222900Snp    final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) {
280222900Snp        for (int i = 0; i < states.getCount(); i++) {
281222900Snp            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
282222900Snp            if (state != null) {
283222900Snp                proc.doState(obj, state);
284222900Snp            }
285222900Snp        }
286222900Snp    }
287222900Snp
288222900Snp    final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) {
289222900Snp        Values hints;
290222900Snp        if (mode == OperandMode.USE) {
291222900Snp            hints = defs;
292222900Snp        } else if (mode == OperandMode.DEF) {
293222900Snp            hints = uses;
294222900Snp        } else {
295222900Snp            return null;
296222900Snp        }
297222900Snp
298222900Snp        for (int i = 0; i < hints.getCount(); i++) {
299222900Snp            if (i < hints.getDirectCount()) {
300222900Snp                Value hintValue = hints.getValue(obj, i);
301222900Snp                Value result = proc.doValue(obj, hintValue, null, null);
302222900Snp                if (result != null) {
303222900Snp                    return result;
304222900Snp                }
305222900Snp            } else {
306222900Snp                Value[] hintValues = hints.getValueArray(obj, i);
307222900Snp                for (int j = 0; j < hintValues.length; j++) {
308222900Snp                    Value hintValue = hintValues[j];
309222900Snp                    Value result = proc.doValue(obj, hintValue, null, null);
310222900Snp                    if (result != null) {
311222900Snp                        return result;
312222900Snp                    }
313222900Snp                }
314222900Snp            }
315222900Snp        }
316222900Snp        return null;
317222900Snp    }
318222900Snp
319222900Snp    String toString(LIRInstruction obj) {
320222900Snp        StringBuilder result = new StringBuilder();
321222900Snp
322222900Snp        appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs);
323222900Snp        result.append(String.valueOf(getOpcode(obj)).toUpperCase());
324222900Snp        appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives);
325222900Snp        appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps);
326222900Snp
327222900Snp        for (int i = 0; i < data.getCount(); i++) {
328222900Snp            if (i == opcodeIndex) {
329222900Snp                continue;
330222900Snp            }
331222900Snp            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
332259048Snp        }
333222900Snp
334222900Snp        for (int i = 0; i < states.getCount(); i++) {
335222900Snp            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
336222900Snp            if (state != null) {
337222900Snp                result.append(" ").append(states.getName(i)).append(" [bci:");
338222900Snp                String sep = "";
339222900Snp                for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) {
340222900Snp                    result.append(sep).append(cur.getBCI());
341222900Snp                    sep = ", ";
342222900Snp                }
343222900Snp                result.append("]");
344259048Snp            }
345222900Snp        }
346222900Snp
347222900Snp        return result.toString();
348222900Snp    }
349222900Snp}
350222900Snp