2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "ControlFlowProfiler.h"
34 ControlFlowProfiler::ControlFlowProfiler()
35 : m_dummyBasicBlock(BasicBlockLocation(-1, -1))
39 ControlFlowProfiler::~ControlFlowProfiler()
41 for (const BlockLocationCache
& cache
: m_sourceIDBuckets
.values()) {
42 for (BasicBlockLocation
* block
: cache
.values())
47 BasicBlockLocation
* ControlFlowProfiler::getBasicBlockLocation(intptr_t sourceID
, int startOffset
, int endOffset
)
49 auto addResult
= m_sourceIDBuckets
.add(sourceID
, BlockLocationCache());
50 BlockLocationCache
& blockLocationCache
= addResult
.iterator
->value
;
51 BasicBlockKey
key(startOffset
, endOffset
);
52 auto addResultForBasicBlock
= blockLocationCache
.add(key
, nullptr);
53 if (addResultForBasicBlock
.isNewEntry
)
54 addResultForBasicBlock
.iterator
->value
= new BasicBlockLocation(startOffset
, endOffset
);
55 return addResultForBasicBlock
.iterator
->value
;
58 void ControlFlowProfiler::dumpData() const
60 auto iter
= m_sourceIDBuckets
.begin();
61 auto end
= m_sourceIDBuckets
.end();
62 for (; iter
!= end
; ++iter
) {
63 dataLog("SourceID: ", iter
->key
, "\n");
64 for (const BasicBlockLocation
* block
: iter
->value
.values())
69 Vector
<BasicBlockRange
> ControlFlowProfiler::getBasicBlocksForSourceID(intptr_t sourceID
, VM
& vm
) const
71 Vector
<BasicBlockRange
> result(0);
72 auto bucketFindResult
= m_sourceIDBuckets
.find(sourceID
);
73 if (bucketFindResult
== m_sourceIDBuckets
.end())
76 const BlockLocationCache
& cache
= bucketFindResult
->value
;
77 for (const BasicBlockLocation
* block
: cache
.values()) {
78 bool hasExecuted
= block
->hasExecuted();
79 const Vector
<BasicBlockLocation::Gap
>& blockRanges
= block
->getExecutedRanges();
80 for (BasicBlockLocation::Gap gap
: blockRanges
) {
81 BasicBlockRange range
;
82 range
.m_hasExecuted
= hasExecuted
;
83 range
.m_startOffset
= gap
.first
;
84 range
.m_endOffset
= gap
.second
;
89 const Vector
<std::tuple
<bool, unsigned, unsigned>>& unexecutedFunctionRanges
= vm
.functionHasExecutedCache()->getFunctionRanges(sourceID
);
90 for (const auto& functionRange
: unexecutedFunctionRanges
) {
91 BasicBlockRange range
;
92 range
.m_hasExecuted
= std::get
<0>(functionRange
);
93 range
.m_startOffset
= static_cast<int>(std::get
<1>(functionRange
));
94 range
.m_endOffset
= static_cast<int>(std::get
<2>(functionRange
));
101 bool ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted(int offset
, intptr_t sourceID
, VM
& vm
)
103 const Vector
<BasicBlockRange
>& blocks
= getBasicBlocksForSourceID(sourceID
, vm
);
104 int bestDistance
= INT_MAX
;
105 BasicBlockRange bestRange
;
106 bestRange
.m_startOffset
= bestRange
.m_endOffset
= -1;
107 bestRange
.m_hasExecuted
= false; // Suppress MSVC warning.
108 // Because some ranges may overlap because of function boundaries, make sure to find the smallest range enclosing the offset.
109 for (BasicBlockRange range
: blocks
) {
110 if (range
.m_startOffset
<= offset
&& offset
<= range
.m_endOffset
&& (range
.m_endOffset
- range
.m_startOffset
) < bestDistance
) {
111 RELEASE_ASSERT(range
.m_endOffset
- range
.m_startOffset
>= 0);
112 bestDistance
= range
.m_endOffset
- range
.m_startOffset
;
117 RELEASE_ASSERT(bestRange
.m_startOffset
!= -1 && bestRange
.m_endOffset
!= -1);
118 return bestRange
.m_hasExecuted
;