stack_map.h revision 29ba1b068fc9f5a8011782c147b1f7732928aac7
199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray/*
299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Copyright (C) 2014 The Android Open Source Project
399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray *
499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Licensed under the Apache License, Version 2.0 (the "License");
599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * you may not use this file except in compliance with the License.
699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * You may obtain a copy of the License at
799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray *
899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray *      http://www.apache.org/licenses/LICENSE-2.0
999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray *
1099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Unless required by applicable law or agreed to in writing, software
1199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * distributed under the License is distributed on an "AS IS" BASIS,
1299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * See the License for the specific language governing permissions and
1499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * limitations under the License.
1599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray */
1699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
1799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray#ifndef ART_RUNTIME_STACK_MAP_H_
1899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray#define ART_RUNTIME_STACK_MAP_H_
1999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
2099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray#include "base/bit_vector.h"
2199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray#include "memory_region.h"
22376b2bbf7c39108223a7a01568a7b4b04d84eeacNicolas Geoffray#include "utils.h"
2399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
2499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffraynamespace art {
2599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
26a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain// Size of a frame slot, in bytes.  This constant is a signed value,
27a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain// to please the compiler in arithmetic operations involving int32_t
28a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain// (signed) values.
29a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillainstatic ssize_t constexpr kFrameSlotSize = 4;
30a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
319ac0e4d4ed1b45cf8767ef1d339afcdd205bf55aRoland Levillain// Word alignment required on ARM, in bytes.
329ac0e4d4ed1b45cf8767ef1d339afcdd205bf55aRoland Levillainstatic constexpr size_t kWordAlignment = 4;
339ac0e4d4ed1b45cf8767ef1d339afcdd205bf55aRoland Levillain
3499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray/**
3599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Classes in the following file are wrapper on stack map information backed
3699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * by a MemoryRegion. As such they read and write to the region, they don't have
3799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * their own fields.
3899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray */
3999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
4099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray/**
4199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Inline information for a specific PC. The information is of the form:
4299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * [inlining_depth, [method_dex reference]+]
4399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray */
4499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffrayclass InlineInfo {
4599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray public:
4699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  explicit InlineInfo(MemoryRegion region) : region_(region) {}
4799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
4899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint8_t GetDepth() const {
4999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint8_t>(kDepthOffset);
5099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
5199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
5299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetDepth(uint8_t depth) {
5399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    region_.Store<uint8_t>(kDepthOffset, depth);
5499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
5599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
5699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
5799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
5899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
5999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
6099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
6199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
6299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
6399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
6499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static size_t SingleEntrySize() {
6599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return sizeof(uint32_t);
6699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
6799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
6899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray private:
69a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // TODO: Instead of plain types such as "uint8_t", introduce
70a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // typedefs (and document the memory layout of InlineInfo).
7199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kDepthOffset = 0;
7299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
7399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
7499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  MemoryRegion region_;
7599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
763946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  friend class CodeInfo;
773946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  friend class StackMap;
783946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  friend class StackMapStream;
7999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray};
8099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
81a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain// Dex register location container used by DexRegisterMap and StackMapStream.
82a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillainclass DexRegisterLocation {
83a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain public:
84a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  /*
85a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * The location kind used to populate the Dex register information in a
86a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * StackMapStream can either be:
87a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kNone: the register has no location yet, meaning it has not been set;
88a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kConstant: value holds the constant;
89a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kStack: value holds the stack offset;
90a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kRegister: value holds the physical register number;
91a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kFpuRegister: value holds the physical register number.
92a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   *
93a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * In addition, DexRegisterMap also uses these values:
94a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kInStackLargeOffset: value holds a "large" stack offset (greater than
95a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   *   128 bytes);
96a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   * - kConstantLargeValue: value holds a "large" constant (lower than or
97a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   *   equal to -16, or greater than 16).
98a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain   */
99a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  enum class Kind : uint8_t {
100a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Short location kinds, for entries fitting on one byte (3 bits
101a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // for the kind, 5 bits for the value) in a DexRegisterMap.
102a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kNone = 0,                // 0b000
103a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kInStack = 1,             // 0b001
104a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kInRegister = 2,          // 0b010
105a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kInFpuRegister = 3,       // 0b011
106a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kConstant = 4,            // 0b100
107a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
108a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Large location kinds, requiring a 5-byte encoding (1 byte for the
109a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // kind, 4 bytes for the value).
110a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
111a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Stack location at a large offset, meaning that the offset value
112a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // divided by the stack frame slot size (4 bytes) cannot fit on a
113a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // 5-bit unsigned integer (i.e., this offset value is greater than
114a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // or equal to 2^5 * 4 = 128 bytes).
115a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kInStackLargeOffset = 5,  // 0b101
116a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
117a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
118a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // lower than -2^(5-1) = -16, or greater than or equal to
119a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // 2^(5-1) - 1 = 15).
120a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kConstantLargeValue = 6,  // 0b110
121a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
122a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    kLastLocationKind = kConstantLargeValue
123a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  };
124a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
125a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static_assert(
126a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      sizeof(Kind) == 1u,
127a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      "art::DexRegisterLocation::Kind has a size different from one byte.");
128a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
129a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static const char* PrettyDescriptor(Kind kind) {
130a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    switch (kind) {
131a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kNone:
132a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "none";
133a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInStack:
134a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "in stack";
135a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInRegister:
136a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "in register";
137a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInFpuRegister:
138a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "in fpu register";
139a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kConstant:
140a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "as constant";
141a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInStackLargeOffset:
142a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "in stack (large offset)";
143a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kConstantLargeValue:
144a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return "as constant (large value)";
145a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      default:
146a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        UNREACHABLE();
147a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
148a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
149a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
150a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static bool IsShortLocationKind(Kind kind) {
151a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    switch (kind) {
152a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kNone:
153a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInStack:
154a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInRegister:
155a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInFpuRegister:
156a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kConstant:
157a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return true;
158a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
159a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInStackLargeOffset:
160a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kConstantLargeValue:
161a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return false;
162a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
163a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      default:
164a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        UNREACHABLE();
165a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
166a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
167a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
168a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Convert `kind` to a "surface" kind, i.e. one that doesn't include
169a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // any value with a "large" qualifier.
170a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // TODO: Introduce another enum type for the surface kind?
171a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static Kind ConvertToSurfaceKind(Kind kind) {
172a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    switch (kind) {
173a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kNone:
174a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInStack:
175a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInRegister:
176a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInFpuRegister:
177a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kConstant:
178a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return kind;
179a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
180a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kInStackLargeOffset:
181a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return Kind::kInStack;
182a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
183a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case Kind::kConstantLargeValue:
184a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return Kind::kConstant;
185a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
186a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      default:
187a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        UNREACHABLE();
188a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
189a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
190a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
191a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  DexRegisterLocation(Kind kind, int32_t value)
192a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      : kind_(kind), value_(value) {}
193a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
194a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Get the "surface" kind of the location, i.e., the one that doesn't
195a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // include any value with a "large" qualifier.
196a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  Kind GetKind() const {
197a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return ConvertToSurfaceKind(kind_);
198a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
199a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
200a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Get the value of the location.
201a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  int32_t GetValue() const { return value_; }
202a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
203a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Get the actual kind of the location.
204a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  Kind GetInternalKind() const { return kind_; }
205a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
206a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain private:
207a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  Kind kind_;
208a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  int32_t value_;
209a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain};
210a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
21199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray/**
21299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Information on dex register values for a specific PC. The information is
21399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * of the form:
21499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * [location_kind, register_value]+.
215a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain * either on 1 or 5 bytes (see art::DexRegisterLocation::Kind).
21699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray */
21799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffrayclass DexRegisterMap {
21899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray public:
21999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
22099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
221a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Short (compressed) location, fitting on one byte.
222a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  typedef uint8_t ShortLocation;
223a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
224a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
225a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
226a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    int32_t value = dex_register_location.GetValue();
227a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    if (DexRegisterLocation::IsShortLocationKind(kind)) {
228a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Short location.  Compress the kind and the value as a single byte.
229a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      if (kind == DexRegisterLocation::Kind::kInStack) {
230a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Instead of storing stack offsets expressed in bytes for
231a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // short stack locations, store slot offsets.  A stack offset
232a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // is a multiple of 4 (kFrameSlotSize).  This means that by
233a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // dividing it by 4, we can fit values from the [0, 128)
234a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // interval in a short stack location, and not just values
235a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // from the [0, 32) interval.
236a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_EQ(value % kFrameSlotSize, 0);
237a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        value /= kFrameSlotSize;
238a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      }
239a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      DCHECK(IsUint<kValueBits>(value)) << value;
240a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
241a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    } else {
242a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Large location.  Write the location on one byte and the value
243a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // on 4 bytes.
244a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      DCHECK(!IsUint<kValueBits>(value)) << value;
245a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
246a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Also divide large stack offsets by 4 for the sake of consistency.
247a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_EQ(value % kFrameSlotSize, 0);
248a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        value /= kFrameSlotSize;
249a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      }
250a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Data can be unaligned as the written Dex register locations can
251a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // either be 1-byte or 5-byte wide.  Use
252a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // art::MemoryRegion::StoreUnaligned instead of
253a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
254a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
255a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
256a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
257a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
25899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
259a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Find the offset of the Dex register location number `dex_register_index`.
260a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  size_t FindLocationOffset(uint16_t dex_register_index) const {
261a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    size_t offset = kFixedSize;
262a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Skip the first `dex_register_index - 1` entries.
263a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    for (uint16_t i = 0; i < dex_register_index; ++i) {
264a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Read the first next byte and inspect its first 3 bits to decide
265a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // whether it is a short or a large location.
266a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
267a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      if (DexRegisterLocation::IsShortLocationKind(kind)) {
268a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Short location.  Skip the current byte.
269a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        offset += SingleShortEntrySize();
270a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      } else {
271a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Large location.  Skip the 5 next bytes.
272a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        offset += SingleLargeEntrySize();
273a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      }
274442b46a087c389a91a0b51547ac9205058432364Roland Levillain    }
275a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return offset;
276442b46a087c389a91a0b51547ac9205058432364Roland Levillain  }
277442b46a087c389a91a0b51547ac9205058432364Roland Levillain
278a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Get the surface kind.
279a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index) const {
280a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return DexRegisterLocation::ConvertToSurfaceKind(GetLocationInternalKind(dex_register_index));
28199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
28299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
283a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Get the internal kind.
284a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index) const {
285a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    size_t offset = FindLocationOffset(dex_register_index);
286a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return ExtractKindAtOffset(offset);
28799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
28899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
289a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // TODO: Rename as GetDexRegisterLocation?
290a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index) const {
291a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    size_t offset = FindLocationOffset(dex_register_index);
292a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Read the first byte and inspect its first 3 bits to get the location.
293a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
294a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
295a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    if (DexRegisterLocation::IsShortLocationKind(kind)) {
296a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Short location.  Extract the value from the remaining 5 bits.
297a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      int32_t value = ExtractValueFromShortLocation(first_byte);
298a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      if (kind == DexRegisterLocation::Kind::kInStack) {
299a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Convert the stack slot (short) offset to a byte offset value.
300a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        value *= kFrameSlotSize;
301a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      }
302a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      return DexRegisterLocation(kind, value);
303a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    } else {
304a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Large location.  Read the four next bytes to get the value.
305a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
306a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
307a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Convert the stack slot (large) offset to a byte offset value.
308a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        value *= kFrameSlotSize;
309a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      }
310a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      return DexRegisterLocation(kind, value);
311a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
31299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
31399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
314a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  int32_t GetStackOffsetInBytes(uint16_t dex_register_index) const {
315a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
316a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
317a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // GetLocationKindAndValue returns the offset in bytes.
318a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return location.GetValue();
3197cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz  }
3207cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
321a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  int32_t GetConstant(uint16_t dex_register_index) const {
322a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
323a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
324a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return location.GetValue();
3257cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz  }
3267cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
327a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  int32_t GetMachineRegister(uint16_t dex_register_index) const {
328a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
329a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
330a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain           || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
331a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
332a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return location.GetValue();
3337cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz  }
3347cde48c56df5b57aed524cce44c902bc720f2d6cSebastien Hertz
335a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Compute the compressed kind of `location`.
336a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
337a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    switch (location.GetInternalKind()) {
338a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kNone:
339a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_EQ(location.GetValue(), 0);
340a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return DexRegisterLocation::Kind::kNone;
341a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
342a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kInRegister:
343a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_GE(location.GetValue(), 0);
344a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
345a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return DexRegisterLocation::Kind::kInRegister;
346a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
347a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kInFpuRegister:
348a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_GE(location.GetValue(), 0);
349a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
350a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return DexRegisterLocation::Kind::kInFpuRegister;
351a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
352a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kInStack:
353a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
354a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return IsUint<DexRegisterMap::kValueBits>(location.GetValue() / kFrameSlotSize)
355a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain            ? DexRegisterLocation::Kind::kInStack
356a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain            : DexRegisterLocation::Kind::kInStackLargeOffset;
357a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
358a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kConstant:
359a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return IsUint<DexRegisterMap::kValueBits>(location.GetValue())
360a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain            ? DexRegisterLocation::Kind::kConstant
361a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain            : DexRegisterLocation::Kind::kConstantLargeValue;
362a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
363a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      default:
364a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        LOG(FATAL) << "Unexpected location kind"
365a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain                   << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
366a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        UNREACHABLE();
367a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
368a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
369a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
370a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Can `location` be turned into a short location?
371a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
372a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    switch (location.GetInternalKind()) {
373a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kNone:
374a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kInRegister:
375a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kInFpuRegister:
376a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return true;
377a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
378a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kInStack:
379a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
380a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return IsUint<kValueBits>(location.GetValue() / kFrameSlotSize);
381a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
382a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      case DexRegisterLocation::Kind::kConstant:
383a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        return IsUint<kValueBits>(location.GetValue());
384a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
385a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      default:
386a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        UNREACHABLE();
387a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
388a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
389a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
390a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static size_t EntrySize(const DexRegisterLocation& location) {
391a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return CanBeEncodedAsShortLocation(location)
392a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        ? DexRegisterMap::SingleShortEntrySize()
393a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        : DexRegisterMap::SingleLargeEntrySize();
394a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
395a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
396a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static size_t SingleShortEntrySize() {
397a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return sizeof(ShortLocation);
398a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
399a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
400a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static size_t SingleLargeEntrySize() {
401a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
40299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
40399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
40412baf476389359d54ae04d7898190ef6f81ab0b2Roland Levillain  size_t Size() const {
40512baf476389359d54ae04d7898190ef6f81ab0b2Roland Levillain    return region_.size();
40612baf476389359d54ae04d7898190ef6f81ab0b2Roland Levillain  }
40712baf476389359d54ae04d7898190ef6f81ab0b2Roland Levillain
40899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kFixedSize = 0;
40999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
41012baf476389359d54ae04d7898190ef6f81ab0b2Roland Levillain private:
411a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Width of the kind "field" in a short location, in bits.
412a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static constexpr size_t kKindBits = 3;
413a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Width of the value "field" in a short location, in bits.
414a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static constexpr size_t kValueBits = 5;
415a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
416a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
417a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
418a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static constexpr size_t kKindOffset = 0;
419a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static constexpr size_t kValueOffset = kKindBits;
420a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
421a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
422a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DCHECK(IsUint<kKindBits>(static_cast<uint8_t>(kind))) << static_cast<uint8_t>(kind);
423a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DCHECK(IsUint<kValueBits>(value)) << value;
424a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return (static_cast<uint8_t>(kind) & kKindMask) << kKindOffset
425a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        | (value & kValueMask) << kValueOffset;
426a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
427a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
428a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
429a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    uint8_t kind = (location >> kKindOffset) & kKindMask;
430a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
431a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return static_cast<DexRegisterLocation::Kind>(kind);
432a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
433a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
434a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  static int32_t ExtractValueFromShortLocation(ShortLocation location) {
435a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return (location >> kValueOffset) & kValueMask;
436a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
437a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
438a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Extract a location kind from the byte at position `offset`.
439a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
440a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
441a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return ExtractKindFromShortLocation(first_byte);
442a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
443a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
44499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  MemoryRegion region_;
445a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
446a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  friend class CodeInfo;
447a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  friend class StackMapStream;
44899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray};
44999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
45099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray/**
45199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * A Stack Map holds compilation information for a specific PC necessary for:
45299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * - Mapping it to a dex PC,
45399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * - Knowing which stack entries are objects,
45499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * - Knowing which registers hold objects,
45599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * - Knowing the inlining information,
45699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * - Knowing the values of dex registers.
45799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray *
45899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * The information is of the form:
4593946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
46099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray *
46199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
46299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * stack size of a method.
46399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray */
46499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffrayclass StackMap {
46599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray public:
46699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  explicit StackMap(MemoryRegion region) : region_(region) {}
46799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
46899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint32_t GetDexPc() const {
46999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kDexPcOffset);
47099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
47199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
47299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetDexPc(uint32_t dex_pc) {
47399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    region_.Store<uint32_t>(kDexPcOffset, dex_pc);
47499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
47599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
4763946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  uint32_t GetNativePcOffset() const {
4773946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray    return region_.Load<uint32_t>(kNativePcOffsetOffset);
47899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
47999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
4803946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  void SetNativePcOffset(uint32_t native_pc_offset) {
481a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
48299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
48399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
48499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint32_t GetDexRegisterMapOffset() const {
48599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
48699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
48799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
48899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetDexRegisterMapOffset(uint32_t offset) {
489a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
49099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
49199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
49299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint32_t GetInlineDescriptorOffset() const {
49399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
49499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
49599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
49699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetInlineDescriptorOffset(uint32_t offset) {
497a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
49899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
49999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
50099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint32_t GetRegisterMask() const {
50199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kRegisterMaskOffset);
50299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
50399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
50499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetRegisterMask(uint32_t mask) {
50599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    region_.Store<uint32_t>(kRegisterMaskOffset, mask);
50699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
50799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
50899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  MemoryRegion GetStackMask() const {
50999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Subregion(kStackMaskOffset, StackMaskSize());
51099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
51199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
51299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetStackMask(const BitVector& sp_map) {
51399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    MemoryRegion region = GetStackMask();
51499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    for (size_t i = 0; i < region.size_in_bits(); i++) {
51599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray      region.StoreBit(i, sp_map.IsBitSet(i));
51699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    }
51799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
51899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
519442b46a087c389a91a0b51547ac9205058432364Roland Levillain  bool HasDexRegisterMap() const {
520442b46a087c389a91a0b51547ac9205058432364Roland Levillain    return GetDexRegisterMapOffset() != kNoDexRegisterMap;
521442b46a087c389a91a0b51547ac9205058432364Roland Levillain  }
522442b46a087c389a91a0b51547ac9205058432364Roland Levillain
52399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  bool HasInlineInfo() const {
524442b46a087c389a91a0b51547ac9205058432364Roland Levillain    return GetInlineDescriptorOffset() != kNoInlineInfo;
52599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
52699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
527442b46a087c389a91a0b51547ac9205058432364Roland Levillain  bool Equals(const StackMap& other) const {
52899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.pointer() == other.region_.pointer()
52999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray       && region_.size() == other.region_.size();
53099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
53199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
5329ac0e4d4ed1b45cf8767ef1d339afcdd205bf55aRoland Levillain  static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) {
533376b2bbf7c39108223a7a01568a7b4b04d84eeacNicolas Geoffray    // On ARM, the stack maps must be 4-byte aligned.
5349ac0e4d4ed1b45cf8767ef1d339afcdd205bf55aRoland Levillain    return RoundUp(StackMap::kFixedSize + stack_mask_size, kWordAlignment);
535376b2bbf7c39108223a7a01568a7b4b04d84eeacNicolas Geoffray  }
536376b2bbf7c39108223a7a01568a7b4b04d84eeacNicolas Geoffray
537442b46a087c389a91a0b51547ac9205058432364Roland Levillain  // Special (invalid) offset for the DexRegisterMapOffset field meaning
538442b46a087c389a91a0b51547ac9205058432364Roland Levillain  // that there is no Dex register map for this stack map.
539442b46a087c389a91a0b51547ac9205058432364Roland Levillain  static constexpr uint32_t kNoDexRegisterMap = -1;
540442b46a087c389a91a0b51547ac9205058432364Roland Levillain
541442b46a087c389a91a0b51547ac9205058432364Roland Levillain  // Special (invalid) offset for the InlineDescriptorOffset field meaning
542442b46a087c389a91a0b51547ac9205058432364Roland Levillain  // that there is no inline info for this stack map.
543442b46a087c389a91a0b51547ac9205058432364Roland Levillain  static constexpr uint32_t kNoInlineInfo = -1;
544442b46a087c389a91a0b51547ac9205058432364Roland Levillain
54599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray private:
546a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // TODO: Instead of plain types such as "uint32_t", introduce
547a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // typedefs (and document the memory layout of StackMap).
54899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kDexPcOffset = 0;
5493946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
5503946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
55199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kInlineDescriptorOffsetOffset =
55299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray      kDexRegisterMapOffsetOffset + sizeof(uint32_t);
55399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
55499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
55599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kStackMaskOffset = kFixedSize;
55699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
55799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  size_t StackMaskSize() const { return region_.size() - kFixedSize; }
55899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
55999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  MemoryRegion region_;
56099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
5613946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  friend class CodeInfo;
5623946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  friend class StackMapStream;
56399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray};
56499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
56599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
56699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray/**
56799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * Wrapper around all compiler information collected for a method.
56899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray * The information is of the form:
5693946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
57099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray */
57199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffrayclass CodeInfo {
57299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray public:
57399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  explicit CodeInfo(MemoryRegion region) : region_(region) {}
57499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
5753946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  explicit CodeInfo(const void* data) {
5763946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray    uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
5773946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray    region_ = MemoryRegion(const_cast<void*>(data), size);
5783946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  }
5793946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray
5803946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  StackMap GetStackMapAt(size_t i) const {
58199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    size_t size = StackMapSize();
5823946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray    return StackMap(GetStackMaps().Subregion(i * size, size));
5833946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  }
5843946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray
5853946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  uint32_t GetOverallSize() const {
5863946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray    return region_.Load<uint32_t>(kOverallSizeOffset);
5873946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  }
5883946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray
5893946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  void SetOverallSize(uint32_t size) {
5903946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray    region_.Store<uint32_t>(kOverallSizeOffset, size);
59199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
59299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
59399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  uint32_t GetStackMaskSize() const {
59499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kStackMaskSizeOffset);
59599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
59699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
59799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetStackMaskSize(uint32_t size) {
59899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    region_.Store<uint32_t>(kStackMaskSizeOffset, size);
59999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
60099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
60199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  size_t GetNumberOfStackMaps() const {
60299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
60399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
60499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
60599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
60699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
60799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
60899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
60929ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain  // Get the size of one stack map of this CodeInfo object, in bytes.
61029ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain  // All stack maps of a CodeInfo have the same size.
61199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  size_t StackMapSize() const {
612376b2bbf7c39108223a7a01568a7b4b04d84eeacNicolas Geoffray    return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
61399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
61499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
61529ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain  // Get the size all the stack maps of this CodeInfo object, in bytes.
61629ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain  size_t StackMapsSize() const {
61729ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain    return StackMapSize() * GetNumberOfStackMaps();
61829ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain  }
61929ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain
620a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  uint32_t GetStackMapsOffset() const {
621a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return kFixedSize;
622a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
623a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
624442b46a087c389a91a0b51547ac9205058432364Roland Levillain  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
625442b46a087c389a91a0b51547ac9205058432364Roland Levillain    DCHECK(stack_map.HasDexRegisterMap());
62699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    uint32_t offset = stack_map.GetDexRegisterMapOffset();
627a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    size_t size = ComputeDexRegisterMapSize(offset, number_of_dex_registers);
628a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return DexRegisterMap(region_.Subregion(offset, size));
62999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
63099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
631442b46a087c389a91a0b51547ac9205058432364Roland Levillain  InlineInfo GetInlineInfoOf(StackMap stack_map) const {
632442b46a087c389a91a0b51547ac9205058432364Roland Levillain    DCHECK(stack_map.HasInlineInfo());
63399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    uint32_t offset = stack_map.GetInlineDescriptorOffset();
63499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    uint8_t depth = region_.Load<uint8_t>(offset);
63599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return InlineInfo(region_.Subregion(offset,
63699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray        InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
63799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
63899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
639442b46a087c389a91a0b51547ac9205058432364Roland Levillain  StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
64099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
6413946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray      StackMap stack_map = GetStackMapAt(i);
64299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray      if (stack_map.GetDexPc() == dex_pc) {
64399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray        return stack_map;
64499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray      }
64599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    }
64699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    LOG(FATAL) << "Unreachable";
6472c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers    UNREACHABLE();
64899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
64999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
650442b46a087c389a91a0b51547ac9205058432364Roland Levillain  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
65199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    // TODO: stack maps are sorted by native pc, we can do a binary search.
65299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
6533946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray      StackMap stack_map = GetStackMapAt(i);
6543946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray      if (stack_map.GetNativePcOffset() == native_pc_offset) {
65599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray        return stack_map;
65699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray      }
65799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    }
65899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    LOG(FATAL) << "Unreachable";
6592c4257be8191c5eefde744e8965fcefc80a0a97dIan Rogers    UNREACHABLE();
66099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
66199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
66299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray private:
663a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // TODO: Instead of plain types such as "uint32_t", introduce
664a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // typedefs (and document the memory layout of CodeInfo).
6653946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  static constexpr int kOverallSizeOffset = 0;
6663946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
66799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
66899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
66999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
67099ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  MemoryRegion GetStackMaps() const {
67199ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray    return region_.size() == 0
67299ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray        ? MemoryRegion()
67329ba1b068fc9f5a8011782c147b1f7732928aac7Roland Levillain        : region_.Subregion(kFixedSize, StackMapsSize());
67499ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  }
67599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
676a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // Compute the size of a Dex register map starting at offset `origin` in
677a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  // `region_` and containing `number_of_dex_registers` locations.
678a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  size_t ComputeDexRegisterMapSize(uint32_t origin, uint32_t number_of_dex_registers) const {
679a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // TODO: Ideally, we would like to use art::DexRegisterMap::Size or
680a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not
681a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // yet built.  Try to factor common code.
682a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    size_t offset = origin + DexRegisterMap::kFixedSize;
683a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    // Skip the first `number_of_dex_registers - 1` entries.
684a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
685a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // Read the first next byte and inspect its first 3 bits to decide
686a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      // whether it is a short or a large location.
687a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      DexRegisterMap::ShortLocation first_byte =
688a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain          region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
689a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      DexRegisterLocation::Kind kind =
690a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain          DexRegisterMap::ExtractKindFromShortLocation(first_byte);
691a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      if (DexRegisterLocation::IsShortLocationKind(kind)) {
692a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Short location.  Skip the current byte.
693a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        offset += DexRegisterMap::SingleShortEntrySize();
694a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      } else {
695a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        // Large location.  Skip the 5 next bytes.
696a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain        offset += DexRegisterMap::SingleLargeEntrySize();
697a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain      }
698a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    }
699a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    size_t size = offset - origin;
700a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain    return size;
701a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain  }
702a2d8ec6876325e89e5d82f5dbeca59f96ced3ec1Roland Levillain
70399ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray  MemoryRegion region_;
7043946844c34ad965515f677084b07d663d70ad1b8Nicolas Geoffray  friend class StackMapStream;
70599ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray};
70699ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
70799ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray}  // namespace art
70899ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray
70999ea58cc68b51837c065f4a2a54efbf208dd76faNicolas Geoffray#endif  // ART_RUNTIME_STACK_MAP_H_
710