1/*
2 * Copyright (C) 2013 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_MAPPING_TABLE_H_
18#define ART_RUNTIME_MAPPING_TABLE_H_
19
20#include "base/logging.h"
21#include "leb128.h"
22
23namespace art {
24
25// A utility for processing the raw uleb128 encoded mapping table created by the quick compiler.
26class MappingTable {
27 public:
28  explicit MappingTable(const uint8_t* encoded_map) : encoded_table_(encoded_map) {
29  }
30
31  uint32_t TotalSize() const PURE {
32    const uint8_t* table = encoded_table_;
33    if (table == nullptr) {
34      return 0;
35    } else {
36      return DecodeUnsignedLeb128(&table);
37    }
38  }
39
40  uint32_t DexToPcSize() const PURE {
41    const uint8_t* table = encoded_table_;
42    if (table == nullptr) {
43      return 0;
44    } else {
45      uint32_t total_size = DecodeUnsignedLeb128(&table);
46      uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
47      return total_size - pc_to_dex_size;
48    }
49  }
50
51  const uint8_t* FirstDexToPcPtr() const {
52    const uint8_t* table = encoded_table_;
53    if (table != nullptr) {
54      uint32_t total_size = DecodeUnsignedLeb128(&table);
55      uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
56      // We must have dex to pc entries or else the loop will go beyond the end of the table.
57      DCHECK_GT(total_size, pc_to_dex_size);
58      for (uint32_t i = 0; i < pc_to_dex_size; ++i) {
59        DecodeUnsignedLeb128(&table);  // Move ptr past native PC delta.
60        DecodeSignedLeb128(&table);  // Move ptr past dex PC delta.
61      }
62    }
63    return table;
64  }
65
66  class DexToPcIterator {
67   public:
68    DexToPcIterator(const MappingTable* table, uint32_t element) :
69        table_(table), element_(element), end_(table_->DexToPcSize()), encoded_table_ptr_(nullptr),
70        native_pc_offset_(0), dex_pc_(0) {
71      if (element == 0) {  // An iterator wanted from the start.
72        if (end_ > 0) {
73          encoded_table_ptr_ = table_->FirstDexToPcPtr();
74          native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
75          // First delta is always positive.
76          dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
77        }
78      } else {  // An iterator wanted from the end.
79        DCHECK_EQ(table_->DexToPcSize(), element);
80      }
81    }
82    uint32_t NativePcOffset() const {
83      return native_pc_offset_;
84    }
85    uint32_t DexPc() const {
86      return dex_pc_;
87    }
88    void operator++() {
89      ++element_;
90      if (element_ != end_) {  // Avoid reading beyond the end of the table.
91        native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
92        // For negative delta, unsigned overflow after static_cast does exactly what we need.
93        dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
94      }
95    }
96    bool operator==(const DexToPcIterator& rhs) const {
97      CHECK(table_ == rhs.table_);
98      return element_ == rhs.element_;
99    }
100    bool operator!=(const DexToPcIterator& rhs) const {
101      CHECK(table_ == rhs.table_);
102      return element_ != rhs.element_;
103    }
104
105   private:
106    const MappingTable* const table_;  // The original table.
107    uint32_t element_;  // A value in the range 0 to end_.
108    const uint32_t end_;  // Equal to table_->DexToPcSize().
109    const uint8_t* encoded_table_ptr_;  // Either nullptr or points to encoded data after this entry.
110    uint32_t native_pc_offset_;  // The current value of native pc offset.
111    uint32_t dex_pc_;  // The current value of dex pc.
112  };
113
114  DexToPcIterator DexToPcBegin() const {
115    return DexToPcIterator(this, 0);
116  }
117
118  DexToPcIterator DexToPcEnd() const {
119    uint32_t size = DexToPcSize();
120    return DexToPcIterator(this, size);
121  }
122
123  uint32_t PcToDexSize() const PURE {
124    const uint8_t* table = encoded_table_;
125    if (table == nullptr) {
126      return 0;
127    } else {
128      DecodeUnsignedLeb128(&table);  // Total_size, unused.
129      uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
130      return pc_to_dex_size;
131    }
132  }
133
134  const uint8_t* FirstPcToDexPtr() const {
135    const uint8_t* table = encoded_table_;
136    if (table != nullptr) {
137      DecodeUnsignedLeb128(&table);  // Total_size, unused.
138      DecodeUnsignedLeb128(&table);  // PC to Dex size, unused.
139    }
140    return table;
141  }
142
143  class PcToDexIterator {
144   public:
145    PcToDexIterator(const MappingTable* table, uint32_t element) :
146        table_(table), element_(element), end_(table_->PcToDexSize()), encoded_table_ptr_(nullptr),
147        native_pc_offset_(0), dex_pc_(0) {
148      if (element == 0) {  // An iterator wanted from the start.
149        if (end_ > 0) {
150          encoded_table_ptr_ = table_->FirstPcToDexPtr();
151          native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
152          // First delta is always positive.
153          dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
154        }
155      } else {  // An iterator wanted from the end.
156        DCHECK_EQ(table_->PcToDexSize(), element);
157      }
158    }
159    uint32_t NativePcOffset() const {
160      return native_pc_offset_;
161    }
162    uint32_t DexPc() const {
163      return dex_pc_;
164    }
165    void operator++() {
166      ++element_;
167      if (element_ != end_) {  // Avoid reading beyond the end of the table.
168        native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
169        // For negative delta, unsigned overflow after static_cast does exactly what we need.
170        dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
171      }
172    }
173    bool operator==(const PcToDexIterator& rhs) const {
174      CHECK(table_ == rhs.table_);
175      return element_ == rhs.element_;
176    }
177    bool operator!=(const PcToDexIterator& rhs) const {
178      CHECK(table_ == rhs.table_);
179      return element_ != rhs.element_;
180    }
181
182   private:
183    const MappingTable* const table_;  // The original table.
184    uint32_t element_;  // A value in the range 0 to PcToDexSize.
185    const uint32_t end_;  // Equal to table_->PcToDexSize().
186    const uint8_t* encoded_table_ptr_;  // Either null or points to encoded data after this entry.
187    uint32_t native_pc_offset_;  // The current value of native pc offset.
188    uint32_t dex_pc_;  // The current value of dex pc.
189  };
190
191  PcToDexIterator PcToDexBegin() const {
192    return PcToDexIterator(this, 0);
193  }
194
195  PcToDexIterator PcToDexEnd() const {
196    uint32_t size = PcToDexSize();
197    return PcToDexIterator(this, size);
198  }
199
200 private:
201  const uint8_t* const encoded_table_;
202};
203
204}  // namespace art
205
206#endif  // ART_RUNTIME_MAPPING_TABLE_H_
207