blob: f77908cffca39595a798ffd7dc6468ebcfea291d [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
126 // Value after modification.
127 DexInstructionIterator& operator++() {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700128 data_.dex_pc_ += Inst().SizeInCodeUnits();
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700129 return *this;
130 }
131
132 // Value before modification.
133 DexInstructionIterator operator++(int) {
134 DexInstructionIterator temp = *this;
135 ++*this;
136 return temp;
137 }
138
Vladimir Markod7559b72017-09-28 13:50:37 +0100139 const value_type& operator*() const {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700140 return data_;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700141 }
142
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700143 const Instruction* operator->() const {
144 return &data_.Inst();
145 }
146
147 // Return the dex pc for the iterator.
148 ALWAYS_INLINE uint32_t DexPc() const {
149 return data_.DexPc();
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700150 }
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700151};
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700152
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700153// A safe version of DexInstructionIterator that is guaranteed to not go past the end of the code
154// item.
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700155class SafeDexInstructionIterator : public DexInstructionIteratorBase {
156 public:
157 explicit SafeDexInstructionIterator(const DexInstructionIteratorBase& start,
158 const DexInstructionIteratorBase& end)
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700159 : DexInstructionIteratorBase(&start.Inst(), start.DexPc())
160 , num_code_units_(end.DexPc()) {
161 DCHECK_EQ(start.Instructions(), end.Instructions())
162 << "start and end must be in the same code item.";
163 }
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700164
165 // Value after modification, does not read past the end of the allowed region. May increment past
166 // the end of the code item though.
167 SafeDexInstructionIterator& operator++() {
168 AssertValid();
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700169 const size_t size_code_units = Inst().CodeUnitsRequiredForSizeComputation();
170 const size_t available = NumCodeUnits() - DexPc();
Mathieu Chartier176190c2017-10-31 09:58:07 -0700171 if (UNLIKELY(size_code_units > available)) {
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700172 error_state_ = true;
Mathieu Chartier176190c2017-10-31 09:58:07 -0700173 return *this;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700174 }
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700175 const size_t instruction_code_units = Inst().SizeInCodeUnits();
176 if (UNLIKELY(instruction_code_units > available)) {
Mathieu Chartier176190c2017-10-31 09:58:07 -0700177 error_state_ = true;
178 return *this;
179 }
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700180 data_.dex_pc_ += instruction_code_units;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700181 return *this;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700182 }
183
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700184 // Value before modification.
185 SafeDexInstructionIterator operator++(int) {
186 SafeDexInstructionIterator temp = *this;
187 ++*this;
188 return temp;
189 }
190
191 const value_type& operator*() const {
192 AssertValid();
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700193 return data_;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700194 }
195
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700196 const Instruction* operator->() const {
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700197 AssertValid();
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700198 return &data_.Inst();
199 }
200
201 // Return the current instruction of the iterator.
202 ALWAYS_INLINE const Instruction& Inst() const {
203 return data_.Inst();
204 }
205
206 const uint16_t* Instructions() const {
207 return data_.Instructions();
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700208 }
209
210 // Returns true if the iterator is in an error state. This occurs when an instruction couldn't
211 // have its size computed without reading past the end iterator.
212 bool IsErrorState() const {
213 return error_state_;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700214 }
215
216 private:
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700217 ALWAYS_INLINE void AssertValid() const {
218 DCHECK(!IsErrorState());
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700219 DCHECK_LT(DexPc(), NumCodeUnits());
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700220 }
221
Mathieu Chartier2b2bef22017-10-26 17:10:19 -0700222 ALWAYS_INLINE uint32_t NumCodeUnits() const {
223 return num_code_units_;
224 }
225
226 const uint32_t num_code_units_ = 0;
Mathieu Chartieraf7c9022017-10-27 09:42:46 -0700227 bool error_state_ = false;
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700228};
229
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -0700230} // namespace art
231
232#endif // ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_