blob: 52eca61c061b7b2f07903685e85b9d62a0288d59 [file] [log] [blame]
Mathieu Chartierde4b08f2017-07-10 14:13:41 -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_QUICKEN_INFO_H_
18#define ART_RUNTIME_QUICKEN_INFO_H_
19
Mathieu Chartier210531f2018-01-12 10:15:51 -080020#include "base/array_ref.h"
David Sehr9e734c72018-01-04 17:56:19 -080021#include "dex/dex_instruction.h"
Mathieu Chartier210531f2018-01-12 10:15:51 -080022#include "leb128.h"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070023
24namespace art {
25
Mathieu Chartier210531f2018-01-12 10:15:51 -080026// Table for getting the offset of quicken info. Doesn't have one slot for each index, so a
27// combination of iteration and indexing is required to get the quicken info for a given dex method
28// index.
29class QuickenInfoOffsetTableAccessor {
30 public:
31 using TableType = uint32_t;
32 static constexpr uint32_t kElementsPerIndex = 16;
33
34 class Builder {
35 public:
36 explicit Builder(std::vector<uint8_t>* out_data) : out_data_(out_data) {}
37
38 void AddOffset(uint32_t index) {
39 out_data_->insert(out_data_->end(),
40 reinterpret_cast<const uint8_t*>(&index),
41 reinterpret_cast<const uint8_t*>(&index + 1));
42 }
43
44 private:
45 std::vector<uint8_t>* const out_data_;
46 };
47
48 // The table only covers every kElementsPerIndex indices.
49 static bool IsCoveredIndex(uint32_t index) {
50 return index % kElementsPerIndex == 0;
51 }
52
53 explicit QuickenInfoOffsetTableAccessor(const uint8_t* data, uint32_t max_index)
54 : table_(reinterpret_cast<const uint32_t*>(data)),
55 num_indices_(RoundUp(max_index, kElementsPerIndex) / kElementsPerIndex) {}
56
57 size_t SizeInBytes() const {
58 return NumIndices() * sizeof(table_[0]);
59 }
60
61 uint32_t NumIndices() const {
62 return num_indices_;
63 }
64
65 // Returns the offset for the index at or before the desired index. If the offset is for an index
66 // before the desired one, remainder is how many elements to traverse to reach the desired index.
67 TableType ElementOffset(uint32_t index, uint32_t* remainder) const {
68 *remainder = index % kElementsPerIndex;
69 return table_[index / kElementsPerIndex];
70 }
71
72 const uint8_t* DataEnd() const {
73 return reinterpret_cast<const uint8_t*>(table_ + NumIndices());
74 }
75
76 static uint32_t Alignment() {
77 return alignof(TableType);
78 }
79
80 private:
81 const TableType* table_;
82 uint32_t num_indices_;
83};
84
85// QuickenInfoTable is a table of 16 bit dex indices. There is one slot for every instruction that
86// is possibly dequickenable.
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070087class QuickenInfoTable {
88 public:
Mathieu Chartier210531f2018-01-12 10:15:51 -080089 class Builder {
90 public:
91 Builder(std::vector<uint8_t>* out_data, size_t num_elements) : out_data_(out_data) {
92 EncodeUnsignedLeb128(out_data_, num_elements);
93 }
94
95 void AddIndex(uint16_t index) {
96 out_data_->push_back(static_cast<uint8_t>(index));
97 out_data_->push_back(static_cast<uint8_t>(index >> 8));
98 }
99
100 private:
101 std::vector<uint8_t>* const out_data_;
102 };
103
104 explicit QuickenInfoTable(ArrayRef<const uint8_t> data)
105 : data_(data.data()),
106 num_elements_(!data.empty() ? DecodeUnsignedLeb128(&data_) : 0u) {}
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700107
108 bool IsNull() const {
109 return data_ == nullptr;
110 }
111
112 uint16_t GetData(size_t index) const {
113 return data_[index * 2] | (static_cast<uint16_t>(data_[index * 2 + 1]) << 8);
114 }
115
116 // Returns true if the dex instruction has an index in the table. (maybe dequickenable).
117 static bool NeedsIndexForInstruction(const Instruction* inst) {
118 return inst->IsQuickened() || inst->Opcode() == Instruction::NOP;
119 }
120
121 static size_t NumberOfIndices(size_t bytes) {
122 return bytes / sizeof(uint16_t);
123 }
124
Mathieu Chartier210531f2018-01-12 10:15:51 -0800125 static size_t SizeInBytes(ArrayRef<const uint8_t> data) {
126 QuickenInfoTable table(data);
127 return table.data_ + table.NumIndices() * 2 - data.data();
128 }
129
130 uint32_t NumIndices() const {
131 return num_elements_;
132 }
133
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700134 private:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800135 const uint8_t* data_;
136 const uint32_t num_elements_;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700137
138 DISALLOW_COPY_AND_ASSIGN(QuickenInfoTable);
139};
140
141} // namespace art
142
143#endif // ART_RUNTIME_QUICKEN_INFO_H_