001/*
002 * Copyright (c) 2012, 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 jdk.internal.jvmci.hotspot;
024
025import jdk.internal.jvmci.meta.*;
026
027public final class HotSpotProfilingInfo implements ProfilingInfo, HotSpotProxified {
028
029    // private static final DebugMetric metricInsufficentSpace =
030    // Debug.metric("InsufficientSpaceForProfilingData");
031
032    private final HotSpotMethodData methodData;
033    private final HotSpotResolvedJavaMethod method;
034
035    private boolean isMature;
036    private int position;
037    private int hintPosition;
038    private int hintBCI;
039    private HotSpotMethodDataAccessor dataAccessor;
040
041    private boolean includeNormal;
042    private boolean includeOSR;
043
044    public HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) {
045        this.methodData = methodData;
046        this.method = method;
047        this.includeNormal = includeNormal;
048        this.includeOSR = includeOSR;
049        this.isMature = methodData.isProfileMature();
050        hintPosition = 0;
051        hintBCI = -1;
052    }
053
054    @Override
055    public int getCodeSize() {
056        return method.getCodeSize();
057    }
058
059    @Override
060    public JavaTypeProfile getTypeProfile(int bci) {
061        if (!isMature) {
062            return null;
063        }
064        findBCI(bci, false);
065        return dataAccessor.getTypeProfile(methodData, position);
066    }
067
068    @Override
069    public JavaMethodProfile getMethodProfile(int bci) {
070        if (!isMature) {
071            return null;
072        }
073        findBCI(bci, false);
074        return dataAccessor.getMethodProfile(methodData, position);
075    }
076
077    @Override
078    public double getBranchTakenProbability(int bci) {
079        if (!isMature) {
080            return -1;
081        }
082        findBCI(bci, false);
083        return dataAccessor.getBranchTakenProbability(methodData, position);
084    }
085
086    @Override
087    public double[] getSwitchProbabilities(int bci) {
088        if (!isMature) {
089            return null;
090        }
091        findBCI(bci, false);
092        return dataAccessor.getSwitchProbabilities(methodData, position);
093    }
094
095    @Override
096    public TriState getExceptionSeen(int bci) {
097        findBCI(bci, true);
098        return dataAccessor.getExceptionSeen(methodData, position);
099    }
100
101    @Override
102    public TriState getNullSeen(int bci) {
103        findBCI(bci, false);
104        return dataAccessor.getNullSeen(methodData, position);
105    }
106
107    @Override
108    public int getExecutionCount(int bci) {
109        if (!isMature) {
110            return -1;
111        }
112        findBCI(bci, false);
113        return dataAccessor.getExecutionCount(methodData, position);
114    }
115
116    @Override
117    public int getDeoptimizationCount(DeoptimizationReason reason) {
118        int count = 0;
119        if (includeNormal) {
120            count += methodData.getDeoptimizationCount(reason);
121        }
122        if (includeOSR) {
123            count += methodData.getOSRDeoptimizationCount(reason);
124        }
125        return count;
126    }
127
128    private void findBCI(int targetBCI, boolean searchExtraData) {
129        assert targetBCI >= 0 : "invalid BCI";
130
131        if (methodData.hasNormalData()) {
132            int currentPosition = targetBCI < hintBCI ? 0 : hintPosition;
133            HotSpotMethodDataAccessor currentAccessor;
134            while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) {
135                int currentBCI = currentAccessor.getBCI(methodData, currentPosition);
136                if (currentBCI == targetBCI) {
137                    normalDataFound(currentAccessor, currentPosition, currentBCI);
138                    return;
139                } else if (currentBCI > targetBCI) {
140                    break;
141                }
142                currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition);
143            }
144        }
145
146        boolean exceptionPossiblyNotRecorded = false;
147        if (searchExtraData && methodData.hasExtraData()) {
148            int currentPosition = methodData.getExtraDataBeginOffset();
149            HotSpotMethodDataAccessor currentAccessor;
150            while ((currentAccessor = methodData.getExtraData(currentPosition)) != null) {
151                int currentBCI = currentAccessor.getBCI(methodData, currentPosition);
152                if (currentBCI == targetBCI) {
153                    extraDataFound(currentAccessor, currentPosition);
154                    return;
155                }
156                currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition);
157            }
158
159            if (!methodData.isWithin(currentPosition)) {
160                exceptionPossiblyNotRecorded = true;
161                // metricInsufficentSpace.increment();
162            }
163        }
164
165        noDataFound(exceptionPossiblyNotRecorded);
166    }
167
168    private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) {
169        setCurrentData(data, pos);
170        this.hintPosition = position;
171        this.hintBCI = bci;
172    }
173
174    private void extraDataFound(HotSpotMethodDataAccessor data, int pos) {
175        setCurrentData(data, pos);
176    }
177
178    private void noDataFound(boolean exceptionPossiblyNotRecorded) {
179        HotSpotMethodDataAccessor accessor = HotSpotMethodData.getNoDataAccessor(exceptionPossiblyNotRecorded);
180        setCurrentData(accessor, -1);
181    }
182
183    private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) {
184        this.dataAccessor = dataAccessor;
185        this.position = position;
186    }
187
188    @Override
189    public boolean isMature() {
190        return isMature;
191    }
192
193    public void ignoreMature() {
194        isMature = true;
195    }
196
197    @Override
198    public String toString() {
199        return "HotSpotProfilingInfo<" + this.toString(null, "; ") + ">";
200    }
201
202    @Override
203    public void setMature() {
204        isMature = true;
205    }
206
207    /**
208     * {@code MethodData::_jvmci_ir_size} (currently) supports at most one JVMCI compiler IR type
209     * which will be determined by the first JVMCI compiler that calls
210     * {@link #setCompilerIRSize(Class, int)}.
211     */
212    private static volatile Class<?> supportedCompilerIRType;
213
214    @Override
215    public boolean setCompilerIRSize(Class<?> irType, int size) {
216        if (supportedCompilerIRType == null) {
217            synchronized (HotSpotProfilingInfo.class) {
218                if (supportedCompilerIRType == null) {
219                    supportedCompilerIRType = irType;
220                }
221            }
222        }
223        if (supportedCompilerIRType != irType) {
224            return false;
225        }
226        methodData.setCompiledIRSize(size);
227        return true;
228    }
229
230    @Override
231    public int getCompilerIRSize(Class<?> irType) {
232        if (irType == supportedCompilerIRType) {
233            return methodData.getCompiledIRSize();
234        }
235        return -1;
236    }
237}