Add a new stack map scheme that encodes compilation info per pc.

Encodes stack mask, register mask, dex register values, and inlining
info. The encoding is currently very straightforward: there is no
clever encoding, nor compression.

Change-Id: I5fd9ae28189a5513cd9e3c8d52c648463207643d
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
new file mode 100644
index 0000000..7d3a48f
--- /dev/null
+++ b/runtime/stack_map.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2014 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_RUNTIME_STACK_MAP_H_
+#define ART_RUNTIME_STACK_MAP_H_
+
+#include "base/bit_vector.h"
+#include "memory_region.h"
+
+namespace art {
+
+/**
+ * Classes in the following file are wrapper on stack map information backed
+ * by a MemoryRegion. As such they read and write to the region, they don't have
+ * their own fields.
+ */
+
+/**
+ * Inline information for a specific PC. The information is of the form:
+ * [inlining_depth, [method_dex reference]+]
+ */
+class InlineInfo {
+ public:
+  explicit InlineInfo(MemoryRegion region) : region_(region) {}
+
+  uint8_t GetDepth() const {
+    return region_.Load<uint8_t>(kDepthOffset);
+  }
+
+  void SetDepth(uint8_t depth) {
+    region_.Store<uint8_t>(kDepthOffset, depth);
+  }
+
+  uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
+    return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
+  }
+
+  void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
+    region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
+  }
+
+  static size_t SingleEntrySize() {
+    return sizeof(uint32_t);
+  }
+
+ private:
+  static constexpr int kDepthOffset = 0;
+  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
+
+  static constexpr uint32_t kNoInlineInfo = -1;
+
+  MemoryRegion region_;
+
+  template<typename T> friend class CodeInfo;
+  template<typename T> friend class StackMap;
+  template<typename T> friend class StackMapStream;
+};
+
+/**
+ * Information on dex register values for a specific PC. The information is
+ * of the form:
+ * [location_kind, register_value]+.
+ *
+ * The location_kind for a Dex register can either be:
+ * - Constant: register_value holds the constant,
+ * - Stack: register_value holds the stack offset,
+ * - Register: register_value holds the register number.
+ */
+class DexRegisterMap {
+ public:
+  explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
+
+  enum LocationKind {
+    kInStack,
+    kInRegister,
+    kConstant
+  };
+
+  LocationKind GetLocationKind(uint16_t register_index) const {
+    return region_.Load<LocationKind>(
+        kFixedSize + register_index * SingleEntrySize());
+  }
+
+  void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
+    size_t entry = kFixedSize + register_index * SingleEntrySize();
+    region_.Store<LocationKind>(entry, kind);
+    region_.Store<int32_t>(entry + sizeof(LocationKind), value);
+  }
+
+  int32_t GetValue(uint16_t register_index) const {
+    return region_.Load<int32_t>(
+        kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
+  }
+
+  static size_t SingleEntrySize() {
+    return sizeof(LocationKind) + sizeof(int32_t);
+  }
+
+ private:
+  static constexpr int kFixedSize = 0;
+
+  MemoryRegion region_;
+
+  template <typename T> friend class CodeInfo;
+  template <typename T> friend class StackMapStream;
+};
+
+/**
+ * A Stack Map holds compilation information for a specific PC necessary for:
+ * - Mapping it to a dex PC,
+ * - Knowing which stack entries are objects,
+ * - Knowing which registers hold objects,
+ * - Knowing the inlining information,
+ * - Knowing the values of dex registers.
+ *
+ * The information is of the form:
+ * [dex_pc, native_pc, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
+ *
+ * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
+ * stack size of a method.
+ */
+template <typename T>
+class StackMap {
+ public:
+  explicit StackMap(MemoryRegion region) : region_(region) {}
+
+  uint32_t GetDexPc() const {
+    return region_.Load<uint32_t>(kDexPcOffset);
+  }
+
+  void SetDexPc(uint32_t dex_pc) {
+    region_.Store<uint32_t>(kDexPcOffset, dex_pc);
+  }
+
+  T GetNativePc() const {
+    return region_.Load<T>(kNativePcOffset);
+  }
+
+  void SetNativePc(T native_pc) {
+    return region_.Store<T>(kNativePcOffset, native_pc);
+  }
+
+  uint32_t GetDexRegisterMapOffset() const {
+    return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
+  }
+
+  void SetDexRegisterMapOffset(uint32_t offset) {
+    return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
+  }
+
+  uint32_t GetInlineDescriptorOffset() const {
+    return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
+  }
+
+  void SetInlineDescriptorOffset(uint32_t offset) {
+    return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
+  }
+
+  uint32_t GetRegisterMask() const {
+    return region_.Load<uint32_t>(kRegisterMaskOffset);
+  }
+
+  void SetRegisterMask(uint32_t mask) {
+    region_.Store<uint32_t>(kRegisterMaskOffset, mask);
+  }
+
+  MemoryRegion GetStackMask() const {
+    return region_.Subregion(kStackMaskOffset, StackMaskSize());
+  }
+
+  void SetStackMask(const BitVector& sp_map) {
+    MemoryRegion region = GetStackMask();
+    for (size_t i = 0; i < region.size_in_bits(); i++) {
+      region.StoreBit(i, sp_map.IsBitSet(i));
+    }
+  }
+
+  bool HasInlineInfo() const {
+    return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
+  }
+
+  bool Equals(const StackMap& other) {
+    return region_.pointer() == other.region_.pointer()
+       && region_.size() == other.region_.size();
+  }
+
+ private:
+  static constexpr int kDexPcOffset = 0;
+  static constexpr int kNativePcOffset = kDexPcOffset + sizeof(uint32_t);
+  static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffset + sizeof(T);
+  static constexpr int kInlineDescriptorOffsetOffset =
+      kDexRegisterMapOffsetOffset + sizeof(uint32_t);
+  static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
+  static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
+  static constexpr int kStackMaskOffset = kFixedSize;
+
+  size_t StackMaskSize() const { return region_.size() - kFixedSize; }
+
+  MemoryRegion region_;
+
+  template <typename U> friend class CodeInfo;
+  template <typename U> friend class StackMapStream;
+};
+
+
+/**
+ * Wrapper around all compiler information collected for a method.
+ * The information is of the form:
+ * [number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
+ */
+template <typename T>
+class CodeInfo {
+ public:
+  explicit CodeInfo(MemoryRegion region) : region_(region) {}
+
+  StackMap<T> GetStackMapAt(size_t i) const {
+    size_t size = StackMapSize();
+    return StackMap<T>(GetStackMaps().Subregion(i * size, size));
+  }
+
+  uint32_t GetStackMaskSize() const {
+    return region_.Load<uint32_t>(kStackMaskSizeOffset);
+  }
+
+  void SetStackMaskSize(uint32_t size) {
+    region_.Store<uint32_t>(kStackMaskSizeOffset, size);
+  }
+
+  size_t GetNumberOfStackMaps() const {
+    return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
+  }
+
+  void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
+    region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
+  }
+
+  size_t StackMapSize() const {
+    return StackMap<T>::kFixedSize + GetStackMaskSize();
+  }
+
+  DexRegisterMap GetDexRegisterMapOf(StackMap<T> stack_map, uint32_t number_of_dex_registers) {
+    uint32_t offset = stack_map.GetDexRegisterMapOffset();
+    return DexRegisterMap(region_.Subregion(offset,
+        DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
+  }
+
+  InlineInfo GetInlineInfoOf(StackMap<T> stack_map) {
+    uint32_t offset = stack_map.GetInlineDescriptorOffset();
+    uint8_t depth = region_.Load<uint8_t>(offset);
+    return InlineInfo(region_.Subregion(offset,
+        InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
+  }
+
+  StackMap<T> GetStackMapForDexPc(uint32_t dex_pc) {
+    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
+      StackMap<T> stack_map = GetStackMapAt(i);
+      if (stack_map.GetDexPc() == dex_pc) {
+        return stack_map;
+      }
+    }
+    LOG(FATAL) << "Unreachable";
+    return StackMap<T>(MemoryRegion());
+  }
+
+  StackMap<T> GetStackMapForNativePc(T native_pc) {
+    // TODO: stack maps are sorted by native pc, we can do a binary search.
+    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
+      StackMap<T> stack_map = GetStackMapAt(i);
+      if (stack_map.GetNativePc() == native_pc) {
+        return stack_map;
+      }
+    }
+    LOG(FATAL) << "Unreachable";
+    return StackMap<T>(MemoryRegion());
+  }
+
+ private:
+  static constexpr int kNumberOfStackMapsOffset = 0;
+  static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
+  static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
+
+  MemoryRegion GetStackMaps() const {
+    return region_.size() == 0
+        ? MemoryRegion()
+        : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
+  }
+
+  MemoryRegion region_;
+  template<typename U> friend class StackMapStream;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_STACK_MAP_H_