1/*
2 * Copyright (c) 2015, 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 */
23package org.graalvm.compiler.microbenchmarks.graal.util;
24
25import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getGraphFromMethodSpec;
26import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getNodes;
27
28import java.util.ArrayList;
29import java.util.List;
30
31import org.openjdk.jmh.annotations.Level;
32import org.openjdk.jmh.annotations.Scope;
33import org.openjdk.jmh.annotations.State;
34import org.openjdk.jmh.annotations.TearDown;
35
36import org.graalvm.compiler.graph.Node;
37import org.graalvm.compiler.graph.NodeClass;
38import org.graalvm.compiler.nodes.StructuredGraph;
39
40/**
41 * State providing the nodes in a graph. Subclasses of this class are annotated with
42 * {@link MethodSpec} to specify the Java method that will be parsed to obtain the original graph.
43 */
44@State(Scope.Benchmark)
45public abstract class NodesState {
46
47    public NodesState() {
48        this.graph = getGraphFromMethodSpec(getClass());
49        this.nodes = getNodes(graph);
50        this.originalNodes = nodes.clone();
51        List<Node> vnln = new ArrayList<>(nodes.length);
52        List<NodePair> list2 = new ArrayList<>(nodes.length);
53        for (int i = 0; i < nodes.length; i++) {
54            Node n = nodes[i];
55            NodeClass<?> nc = n.getNodeClass();
56            if (nc.valueNumberable() && nc.isLeafNode()) {
57                vnln.add(n);
58            }
59            for (int j = i + i; j < nodes.length; j++) {
60                Node o = nodes[j];
61                if (o.getClass() == n.getClass()) {
62                    list2.add(new NodePair(n, o));
63                }
64            }
65        }
66        valueNumberableLeafNodes = vnln.toArray(new Node[vnln.size()]);
67        valueEqualsNodePairs = list2.toArray(new NodePair[list2.size()]);
68    }
69
70    /**
71     * Used to check that benchmark does not mutate {@link #nodes}.
72     */
73    private final Node[] originalNodes;
74
75    /**
76     * The nodes processed by the benchmark. These arrays must be treated as read-only within the
77     * benchmark method.
78     */
79    public final StructuredGraph graph;
80    public final Node[] nodes;
81    public final Node[] valueNumberableLeafNodes;
82    public final NodePair[] valueEqualsNodePairs;
83
84    public final class NodePair {
85        public final Node n1;
86        public final Node n2;
87
88        public NodePair(Node n1, Node n2) {
89            this.n1 = n1;
90            this.n2 = n2;
91        }
92    }
93
94    private int invocation;
95
96    @TearDown(Level.Invocation)
97    public void afterInvocation() {
98        if (invocation == 0) {
99            // Only need to check the first invocation
100            invocation++;
101            for (int i = 0; i < nodes.length; i++) {
102                if (nodes[i] != originalNodes[i]) {
103                    throw new InternalError(String.format("Benchmark method mutated node %d: original=%s, current=%s", i, originalNodes[i], nodes[i]));
104                }
105            }
106        }
107    }
108}
109