blob: be583a2533b3ea7efed796b27f9461e72a56ec54 [file] [log] [blame]
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
18#define ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
19
20#include <iterator>
21
22#include "dex_instruction.h"
23#include "base/logging.h"
24
25namespace art {
26
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070027class DexInstructionPcPair {
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -070028 public:
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070029 ALWAYS_INLINE const Instruction& Inst() const {
30 return *Instruction::At(instructions_ + DexPc());
Mathieu Chartieraf7c9022017-10-27 09:42:46 -070031 }
32
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070033 ALWAYS_INLINE const Instruction* operator->() const {
34 return &Inst();
35 }
36
37 ALWAYS_INLINE uint32_t DexPc() const {
38 return dex_pc_;
39 }
40
41 ALWAYS_INLINE const uint16_t* Instructions() const {
42 return instructions_;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -070043 }
44
45 protected:
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070046 explicit DexInstructionPcPair(const uint16_t* instructions, uint32_t dex_pc)
47 : instructions_(instructions), dex_pc_(dex_pc) {}
48
49 const uint16_t* instructions_ = nullptr;
50 uint32_t dex_pc_ = 0;
51
52 friend class DexInstructionIteratorBase;
53 friend class DexInstructionIterator;
54 friend class SafeDexInstructionIterator;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -070055};
56
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070057// Base helper class to prevent duplicated comparators.
58class DexInstructionIteratorBase : public
59 std::iterator<std::forward_iterator_tag, DexInstructionPcPair> {
60 public:
61 using value_type = std::iterator<std::forward_iterator_tag, DexInstructionPcPair>::value_type;
62 using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type;
63
64 DexInstructionIteratorBase() = default;
65 explicit DexInstructionIteratorBase(const Instruction* inst, uint32_t dex_pc)
66 : data_(reinterpret_cast<const uint16_t*>(inst), dex_pc) {}
67
68 const Instruction& Inst() const {
69 return data_.Inst();
70 }
71
72 // Return the dex pc for an iterator compared to the code item begin.
73 ALWAYS_INLINE uint32_t DexPc() const {
74 return data_.DexPc();
75 }
76
77 // Instructions from the start of the code item.
78 ALWAYS_INLINE const uint16_t* Instructions() const {
79 return data_.Instructions();
80 }
81
82 protected:
83 DexInstructionPcPair data_;
84};
Mathieu Chartieraf7c9022017-10-27 09:42:46 -070085
86static ALWAYS_INLINE inline bool operator==(const DexInstructionIteratorBase& lhs,
87 const DexInstructionIteratorBase& rhs) {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070088 DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
89 return lhs.DexPc() == rhs.DexPc();
Mathieu Chartieraf7c9022017-10-27 09:42:46 -070090}
91
92static inline bool operator!=(const DexInstructionIteratorBase& lhs,
93 const DexInstructionIteratorBase& rhs) {
94 return !(lhs == rhs);
95}
96
97static inline bool operator<(const DexInstructionIteratorBase& lhs,
98 const DexInstructionIteratorBase& rhs) {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -070099 DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
100 return lhs.DexPc() < rhs.DexPc();
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700101}
102
103static inline bool operator>(const DexInstructionIteratorBase& lhs,
104 const DexInstructionIteratorBase& rhs) {
105 return rhs < lhs;
106}
107
108static inline bool operator<=(const DexInstructionIteratorBase& lhs,
109 const DexInstructionIteratorBase& rhs) {
110 return !(rhs < lhs);
111}
112
113static inline bool operator>=(const DexInstructionIteratorBase& lhs,
114 const DexInstructionIteratorBase& rhs) {
115 return !(lhs < rhs);
116}
117
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700118// A helper class for a code_item's instructions using range based for loop syntax.
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700119class DexInstructionIterator : public DexInstructionIteratorBase {
120 public:
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700121 using DexInstructionIteratorBase::DexInstructionIteratorBase;
122
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700123 explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
124 : DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {}
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700125
Mathieu Chartier0021feb2017-11-07 00:08:52 -0800126 explicit DexInstructionIterator(const DexInstructionPcPair& pair)
127 : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {}
128
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700129 // Value after modification.
130 DexInstructionIterator& operator++() {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700131 data_.dex_pc_ += Inst().SizeInCodeUnits();
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700132 return *this;
133 }
134
135 // Value before modification.
136 DexInstructionIterator operator++(int) {
137 DexInstructionIterator temp = *this;
138 ++*this;
139 return temp;
140 }
141
Vladimir Markod7559b72017-09-28 13:50:37 +0100142 const value_type& operator*() const {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700143 return data_;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700144 }
145
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700146 const Instruction* operator->() const {
147 return &data_.Inst();
148 }
149
150 // Return the dex pc for the iterator.
151 ALWAYS_INLINE uint32_t DexPc() const {
152 return data_.DexPc();
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700153 }
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700154};
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700155
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700156// A safe version of DexInstructionIterator that is guaranteed to not go past the end of the code
157// item.
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700158class SafeDexInstructionIterator : public DexInstructionIteratorBase {
159 public:
160 explicit SafeDexInstructionIterator(const DexInstructionIteratorBase& start,
161 const DexInstructionIteratorBase& end)
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700162 : DexInstructionIteratorBase(&start.Inst(), start.DexPc())
163 , num_code_units_(end.DexPc()) {
164 DCHECK_EQ(start.Instructions(), end.Instructions())
165 << "start and end must be in the same code item.";
166 }
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700167
168 // Value after modification, does not read past the end of the allowed region. May increment past
169 // the end of the code item though.
170 SafeDexInstructionIterator& operator++() {
171 AssertValid();
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700172 const size_t size_code_units = Inst().CodeUnitsRequiredForSizeComputation();
173 const size_t available = NumCodeUnits() - DexPc();
Mathieu Chartier176190c2017-10-31 09:58:07 -0700174 if (UNLIKELY(size_code_units > available)) {
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700175 error_state_ = true;
Mathieu Chartier176190c2017-10-31 09:58:07 -0700176 return *this;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700177 }
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700178 const size_t instruction_code_units = Inst().SizeInCodeUnits();
179 if (UNLIKELY(instruction_code_units > available)) {
Mathieu Chartier176190c2017-10-31 09:58:07 -0700180 error_state_ = true;
181 return *this;
182 }
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700183 data_.dex_pc_ += instruction_code_units;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700184 return *this;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700185 }
186
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700187 // Value before modification.
188 SafeDexInstructionIterator operator++(int) {
189 SafeDexInstructionIterator temp = *this;
190 ++*this;
191 return temp;
192 }
193
194 const value_type& operator*() const {
195 AssertValid();
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700196 return data_;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700197 }
198
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700199 const Instruction* operator->() const {
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700200 AssertValid();
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700201 return &data_.Inst();
202 }
203
204 // Return the current instruction of the iterator.
205 ALWAYS_INLINE const Instruction& Inst() const {
206 return data_.Inst();
207 }
208
209 const uint16_t* Instructions() const {
210 return data_.Instructions();
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700211 }
212
213 // Returns true if the iterator is in an error state. This occurs when an instruction couldn't
214 // have its size computed without reading past the end iterator.
215 bool IsErrorState() const {
216 return error_state_;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700217 }
218
219 private:
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700220 ALWAYS_INLINE void AssertValid() const {
221 DCHECK(!IsErrorState());
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700222 DCHECK_LT(DexPc(), NumCodeUnits());
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700223 }
224
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700225 ALWAYS_INLINE uint32_t NumCodeUnits() const {
226 return num_code_units_;
227 }
228
229 const uint32_t num_code_units_ = 0;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700230 bool error_state_ = false;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700231};
232
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700233} // namespace art
234
235#endif // ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_