File: bytecode_utils.h

package info (click to toggle)
android-platform-art 11.0.0%2Br48-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 78,932 kB
  • sloc: cpp: 459,858; java: 163,268; asm: 22,644; python: 9,815; sh: 6,330; ansic: 4,117; xml: 2,855; perl: 77; makefile: 73
file content (147 lines) | stat: -rw-r--r-- 4,697 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_LIBDEXFILE_DEX_BYTECODE_UTILS_H_
#define ART_LIBDEXFILE_DEX_BYTECODE_UTILS_H_

#include "base/value_object.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file.h"
#include "dex/dex_instruction-inl.h"

namespace art {

class DexSwitchTable : public ValueObject {
 public:
  DexSwitchTable(const Instruction& instruction, uint32_t dex_pc)
      : instruction_(instruction),
        dex_pc_(dex_pc),
        sparse_(instruction.Opcode() == Instruction::SPARSE_SWITCH) {
    int32_t table_offset = instruction.VRegB_31t();
    const uint16_t* table = reinterpret_cast<const uint16_t*>(&instruction) + table_offset;
    DCHECK_EQ(table[0], sparse_ ? static_cast<uint16_t>(Instruction::kSparseSwitchSignature)
                                : static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
    num_entries_ = table[1];
    values_ = reinterpret_cast<const int32_t*>(&table[2]);
  }

  uint16_t GetNumEntries() const {
    return num_entries_;
  }

  void CheckIndex(size_t index) const {
    if (sparse_) {
      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
      DCHECK_LT(index, 2 * static_cast<size_t>(num_entries_));
    } else {
      // In a packed table, we have the starting key and num_entries_ values.
      DCHECK_LT(index, 1 + static_cast<size_t>(num_entries_));
    }
  }

  int32_t GetEntryAt(size_t index) const {
    CheckIndex(index);
    return values_[index];
  }

  uint32_t GetDexPcForIndex(size_t index) const {
    CheckIndex(index);
    return dex_pc_ +
        (reinterpret_cast<const int16_t*>(values_ + index) -
         reinterpret_cast<const int16_t*>(&instruction_));
  }

  // Index of the first value in the table.
  size_t GetFirstValueIndex() const {
    if (sparse_) {
      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
      return num_entries_;
    } else {
      // In a packed table, we have the starting key and num_entries_ values.
      return 1;
    }
  }

  bool IsSparse() const { return sparse_; }

  bool ShouldBuildDecisionTree() {
    return IsSparse() || GetNumEntries() <= kSmallSwitchThreshold;
  }

 private:
  const Instruction& instruction_;
  const uint32_t dex_pc_;

  // Whether this is a sparse-switch table (or a packed-switch one).
  const bool sparse_;

  // This can't be const as it needs to be computed off of the given instruction, and complicated
  // expressions in the initializer list seemed very ugly.
  uint16_t num_entries_;

  const int32_t* values_;

  // The number of entries in a packed switch before we use a jump table or specified
  // compare/jump series.
  static constexpr uint16_t kSmallSwitchThreshold = 3;

  DISALLOW_COPY_AND_ASSIGN(DexSwitchTable);
};

class DexSwitchTableIterator {
 public:
  explicit DexSwitchTableIterator(const DexSwitchTable& table)
      : table_(table),
        num_entries_(static_cast<size_t>(table_.GetNumEntries())),
        first_target_offset_(table_.GetFirstValueIndex()),
        index_(0u) {}

  bool Done() const { return index_ >= num_entries_; }
  bool IsLast() const { return index_ == num_entries_ - 1; }

  void Advance() {
    DCHECK(!Done());
    index_++;
  }

  int32_t CurrentKey() const {
    return table_.IsSparse() ? table_.GetEntryAt(index_) : table_.GetEntryAt(0) + index_;
  }

  int32_t CurrentTargetOffset() const {
    return table_.GetEntryAt(index_ + first_target_offset_);
  }

  uint32_t GetDexPcForCurrentIndex() const { return table_.GetDexPcForIndex(index_); }

 private:
  const DexSwitchTable& table_;
  const size_t num_entries_;
  const size_t first_target_offset_;

  size_t index_;
};

inline bool IsThrowingDexInstruction(const Instruction& instruction) {
  // Special-case MONITOR_EXIT which is a throwing instruction but the verifier
  // guarantees that it will never throw. This is necessary to avoid rejecting
  // 'synchronized' blocks/methods.
  return instruction.IsThrow() && instruction.Opcode() != Instruction::MONITOR_EXIT;
}

}  // namespace art

#endif  // ART_LIBDEXFILE_DEX_BYTECODE_UTILS_H_