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.replacements;
024
025import static com.oracle.graal.compiler.common.GraalOptions.*;
026import static com.oracle.graal.replacements.SnippetTemplate.*;
027import static jdk.internal.jvmci.common.UnsafeAccess.*;
028
029import java.util.*;
030
031import jdk.internal.jvmci.code.*;
032import jdk.internal.jvmci.common.*;
033import jdk.internal.jvmci.meta.*;
034
035import com.oracle.graal.api.replacements.*;
036import com.oracle.graal.compiler.common.type.*;
037import com.oracle.graal.graph.*;
038import com.oracle.graal.nodeinfo.*;
039import com.oracle.graal.nodes.*;
040import com.oracle.graal.nodes.spi.*;
041import com.oracle.graal.phases.util.*;
042import com.oracle.graal.replacements.Snippet.ConstantParameter;
043import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
044import com.oracle.graal.replacements.SnippetTemplate.Arguments;
045import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
046import com.oracle.graal.word.*;
047
048/**
049 * This node can be used to add a counter to the code that will estimate the dynamic number of calls
050 * by adding an increment to the compiled code. This should of course only be used for
051 * debugging/testing purposes.
052 *
053 * A unique counter will be created for each unique name passed to the constructor. Depending on the
054 * value of withContext, the name of the root method is added to the counter's name.
055 */
056@NodeInfo
057public class SnippetCounterNode extends FixedWithNextNode implements Lowerable {
058
059    public static final NodeClass<SnippetCounterNode> TYPE = NodeClass.create(SnippetCounterNode.class);
060
061    @Input protected ValueNode increment;
062
063    protected final SnippetCounter counter;
064
065    public SnippetCounterNode(SnippetCounter counter, ValueNode increment) {
066        super(TYPE, StampFactory.forVoid());
067        this.counter = counter;
068        this.increment = increment;
069    }
070
071    public SnippetCounter getCounter() {
072        return counter;
073    }
074
075    public ValueNode getIncrement() {
076        return increment;
077    }
078
079    @NodeIntrinsic
080    public static native void add(@ConstantNodeParameter SnippetCounter counter, int increment);
081
082    public static void increment(@ConstantNodeParameter SnippetCounter counter) {
083        add(counter, 1);
084    }
085
086    public void lower(LoweringTool tool) {
087        if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
088            SnippetCounterSnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(SnippetCounterSnippets.Templates.class);
089            templates.lower(this, tool);
090        }
091    }
092
093    /**
094     * When {@link #SnippetCounters} are enabled make sure {@link #SNIPPET_COUNTER_LOCATION} is part
095     * of the private locations.
096     *
097     * @param privateLocations
098     * @return a copy of privateLocations with any needed locations added
099     */
100    public static LocationIdentity[] addSnippetCounters(LocationIdentity[] privateLocations) {
101        if (SnippetCounters.getValue()) {
102            for (LocationIdentity location : privateLocations) {
103                if (location.equals(SNIPPET_COUNTER_LOCATION)) {
104                    return privateLocations;
105                }
106            }
107            LocationIdentity[] result = Arrays.copyOf(privateLocations, privateLocations.length + 1);
108            result[result.length - 1] = SnippetCounterNode.SNIPPET_COUNTER_LOCATION;
109            return result;
110        }
111        return privateLocations;
112    }
113
114    /**
115     * We do not want to use the {@link LocationIdentity} of the {@link SnippetCounter#value} field,
116     * so that the usage in snippets is always possible. If a method accesses the counter via the
117     * field and the snippet, the result might not be correct though.
118     */
119    public static final LocationIdentity SNIPPET_COUNTER_LOCATION = NamedLocationIdentity.mutable("SnippetCounter");
120
121    static class SnippetCounterSnippets implements Snippets {
122
123        @Fold
124        private static int countOffset() {
125            try {
126                return (int) unsafe.objectFieldOffset(SnippetCounter.class.getDeclaredField("value"));
127            } catch (Exception e) {
128                throw new JVMCIError(e);
129            }
130        }
131
132        @Snippet
133        public static void add(@ConstantParameter SnippetCounter counter, int increment) {
134            long loadedValue = ObjectAccess.readLong(counter, countOffset(), SNIPPET_COUNTER_LOCATION);
135            ObjectAccess.writeLong(counter, countOffset(), loadedValue + increment, SNIPPET_COUNTER_LOCATION);
136        }
137
138        public static class Templates extends AbstractTemplates {
139
140            private final SnippetInfo add = snippet(SnippetCounterSnippets.class, "add", SNIPPET_COUNTER_LOCATION);
141
142            public Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
143                super(providers, snippetReflection, target);
144            }
145
146            public void lower(SnippetCounterNode counter, LoweringTool tool) {
147                StructuredGraph graph = counter.graph();
148                Arguments args = new Arguments(add, graph.getGuardsStage(), tool.getLoweringStage());
149                args.addConst("counter", counter.getCounter());
150                args.add("increment", counter.getIncrement());
151
152                template(args).instantiate(providers.getMetaAccess(), counter, DEFAULT_REPLACER, args);
153            }
154        }
155    }
156
157}