115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky/*
215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * Copyright (C) 2015 The Android Open Source Project
315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky *
415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * Licensed under the Apache License, Version 2.0 (the "License");
515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * you may not use this file except in compliance with the License.
615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * You may obtain a copy of the License at
715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky *
815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky *      http://www.apache.org/licenses/LICENSE-2.0
915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky *
1015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * Unless required by applicable law or agreed to in writing, software
1115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * distributed under the License is distributed on an "AS IS" BASIS,
1215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * See the License for the specific language governing permissions and
1415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky * limitations under the License.
1515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky */
1615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
1715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky#ifndef ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
1815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky#define ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
1915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
2041b175aba41c9365a1c53b8a1afbd17129c87c14Vladimir Marko#include "base/bit_utils.h"
217c869b352d122ab0bbf7cb529b45fc0365837c3aDavid Srbecky#include "dwarf/dwarf_constants.h"
227c869b352d122ab0bbf7cb529b45fc0365837c3aDavid Srbecky#include "dwarf/register.h"
237c869b352d122ab0bbf7cb529b45fc0365837c3aDavid Srbecky#include "dwarf/writer.h"
2415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
2515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbeckynamespace art {
2615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbeckynamespace dwarf {
2715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
2815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky// Writer for .debug_frame opcodes (DWARF-3).
2915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky// See the DWARF specification for the precise meaning of the opcodes.
3015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky// The writer is very light-weight, however it will do the following for you:
3115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky//  * Choose the most compact encoding of a given opcode.
3215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky//  * Keep track of current state and convert absolute values to deltas.
3315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky//  * Divide by header-defined factors as appropriate.
3415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbeckytemplate<typename Allocator = std::allocator<uint8_t> >
3515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbeckyclass DebugFrameOpCodeWriter : private Writer<Allocator> {
3615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky public:
3715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // To save space, DWARF divides most offsets by header-defined factors.
3815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // They are used in integer divisions, so we make them constants.
3915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // We usually subtract from stack base pointer, so making the factor
4015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // negative makes the encoded values positive and thus easier to encode.
4115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  static constexpr int kDataAlignmentFactor = -4;
4215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  static constexpr int kCodeAlignmentFactor = 1;
4315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
4415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // Explicitely advance the program counter to given location.
45c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE AdvancePC(int absolute_pc) {
4615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    DCHECK_GE(absolute_pc, current_pc_);
47c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
48c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      int delta = FactorCodeOffset(absolute_pc - current_pc_);
49c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      if (delta != 0) {
50c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        if (delta <= 0x3F) {
51c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_advance_loc | delta);
52c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        } else if (delta <= UINT8_MAX) {
53c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_advance_loc1);
54c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(delta);
55c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        } else if (delta <= UINT16_MAX) {
56c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_advance_loc2);
57c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint16(delta);
58c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        } else {
59c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_advance_loc4);
60c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint32(delta);
61c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        }
6215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      }
63c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      current_pc_ = absolute_pc;
6415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
6515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
6615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
6715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // Override this method to automatically advance the PC before each opcode.
6815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  virtual void ImplicitlyAdvancePC() { }
6915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
7015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // Common alias in assemblers - spill relative to current stack pointer.
71c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE RelOffset(Reg reg, int offset) {
7215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    Offset(reg, offset - current_cfa_offset_);
7315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
7415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
7515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // Common alias in assemblers - increase stack frame size.
76c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE AdjustCFAOffset(int delta) {
7715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    DefCFAOffset(current_cfa_offset_ + delta);
7815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
7915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
8015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // Custom alias - spill many registers based on bitmask.
81c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE RelOffsetForMany(Reg reg_base, int offset,
82c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                      uint32_t reg_mask, int reg_size) {
8315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    DCHECK(reg_size == 4 || reg_size == 8);
84c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
85c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      for (int i = 0; reg_mask != 0u; reg_mask >>= 1, i++) {
86c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        // Skip zero bits and go to the set bit.
87c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        int num_zeros = CTZ(reg_mask);
88c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        i += num_zeros;
89c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        reg_mask >>= num_zeros;
9015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        RelOffset(Reg(reg_base.num() + i), offset);
9115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        offset += reg_size;
9215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      }
9315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
9415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
9515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
9615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // Custom alias - unspill many registers based on bitmask.
97c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE RestoreMany(Reg reg_base, uint32_t reg_mask) {
98c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
99c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      for (int i = 0; reg_mask != 0u; reg_mask >>= 1, i++) {
100c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        // Skip zero bits and go to the set bit.
101c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        int num_zeros = CTZ(reg_mask);
102c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        i += num_zeros;
103c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        reg_mask >>= num_zeros;
10415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        Restore(Reg(reg_base.num() + i));
10515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      }
10615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
10715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
10815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
109c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE Nop() {
110c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
111c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_nop);
112c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
11315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
11415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
115c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE Offset(Reg reg, int offset) {
116c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
117c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
118c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      int factored_offset = FactorDataOffset(offset);  // May change sign.
119c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      if (factored_offset >= 0) {
120c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        if (0 <= reg.num() && reg.num() <= 0x3F) {
121c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_offset | reg.num());
122c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUleb128(factored_offset);
123c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        } else {
124c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_offset_extended);
125c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUleb128(reg.num());
126c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUleb128(factored_offset);
127c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        }
12815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      } else {
129c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        uses_dwarf3_features_ = true;
130c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_offset_extended_sf);
13115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        this->PushUleb128(reg.num());
132c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushSleb128(factored_offset);
13315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      }
13415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
13515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
13615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
137c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE Restore(Reg reg) {
138c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
139c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
140c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      if (0 <= reg.num() && reg.num() <= 0x3F) {
141c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_restore | reg.num());
142c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      } else {
143c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_restore_extended);
144c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUleb128(reg.num());
145c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      }
14615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
14715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
14815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
149c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE Undefined(Reg reg) {
150c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
151c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
152c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_undefined);
153c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(reg.num());
154c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
15515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
15615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
157c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE SameValue(Reg reg) {
158c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
159c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
160c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_same_value);
161c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(reg.num());
162c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
16315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
16415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
16515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  // The previous value of "reg" is stored in register "new_reg".
166c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE Register(Reg reg, Reg new_reg) {
167c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
168c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
169c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_register);
170c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(reg.num());
171c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(new_reg.num());
172c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
17315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
17415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
175c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE RememberState() {
176c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
177c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
178c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_remember_state);
17915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
18015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
18115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
182c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE RestoreState() {
183c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
184c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
185c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_restore_state);
186c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
18715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
18815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
189c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE DefCFA(Reg reg, int offset) {
190c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
19115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      ImplicitlyAdvancePC();
19215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      if (offset >= 0) {
193c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_def_cfa);
194c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUleb128(reg.num());
19515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        this->PushUleb128(offset);  // Non-factored.
19615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      } else {
19715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        uses_dwarf3_features_ = true;
198c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_def_cfa_sf);
199c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUleb128(reg.num());
20015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        this->PushSleb128(FactorDataOffset(offset));
20115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      }
20215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
203c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    current_cfa_offset_ = offset;
20415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
20515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
206c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE DefCFARegister(Reg reg) {
207c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
208c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
209c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_def_cfa_register);
21015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      this->PushUleb128(reg.num());
21115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    }
21215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
21315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
214c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE DefCFAOffset(int offset) {
215c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
216c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      if (current_cfa_offset_ != offset) {
217c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        ImplicitlyAdvancePC();
218c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        if (offset >= 0) {
219c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_def_cfa_offset);
220c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUleb128(offset);  // Non-factored.
221c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        } else {
222c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          uses_dwarf3_features_ = true;
223c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushUint8(DW_CFA_def_cfa_offset_sf);
224c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky          this->PushSleb128(FactorDataOffset(offset));
225c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        }
226c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      }
227c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
228c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    // Uncoditional so that the user can still get and check the value.
229c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    current_cfa_offset_ = offset;
23015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
23115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
232c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE ValOffset(Reg reg, int offset) {
233c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
234c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
235c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      uses_dwarf3_features_ = true;
236c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      int factored_offset = FactorDataOffset(offset);  // May change sign.
237c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      if (factored_offset >= 0) {
238c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_val_offset);
239c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUleb128(reg.num());
240c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUleb128(factored_offset);
241c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      } else {
242c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUint8(DW_CFA_val_offset_sf);
243c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushUleb128(reg.num());
244c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        this->PushSleb128(factored_offset);
245c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      }
246c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
24715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
24815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
249c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE DefCFAExpression(void * expr, int expr_size) {
250c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
251c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
252c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      uses_dwarf3_features_ = true;
253c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_def_cfa_expression);
254c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(expr_size);
255c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushData(expr, expr_size);
256c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
25715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
25815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
259c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE Expression(Reg reg, void * expr, int expr_size) {
260c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
261c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
262c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      uses_dwarf3_features_ = true;
263c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_expression);
264c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(reg.num());
265c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(expr_size);
266c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushData(expr, expr_size);
267c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
2681109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky  }
2691109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky
270c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void ALWAYS_INLINE ValExpression(Reg reg, void * expr, int expr_size) {
271c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (UNLIKELY(enabled_)) {
272c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      ImplicitlyAdvancePC();
273c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      uses_dwarf3_features_ = true;
274c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUint8(DW_CFA_val_expression);
275c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(reg.num());
276c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushUleb128(expr_size);
277c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      this->PushData(expr, expr_size);
278c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
27915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
28015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
281c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  bool IsEnabled() const { return enabled_; }
282c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky
283c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void SetEnabled(bool value) { enabled_ = value; }
284c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky
285c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  int GetCurrentPC() const { return current_pc_; }
286c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky
287c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  int GetCurrentCFAOffset() const { return current_cfa_offset_; }
288c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky
289c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  void SetCurrentCFAOffset(int offset) { current_cfa_offset_ = offset; }
29015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
29115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  using Writer<Allocator>::data;
29215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
293c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  DebugFrameOpCodeWriter(bool enabled = true,
294c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                         const Allocator& alloc = Allocator())
29515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky      : Writer<Allocator>(&opcodes_),
296c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky        enabled_(enabled),
29715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        opcodes_(alloc),
29815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        current_cfa_offset_(0),
29915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        current_pc_(0),
30015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky        uses_dwarf3_features_(false) {
301c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    if (enabled) {
302c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      // Best guess based on couple of observed outputs.
303c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky      opcodes_.reserve(16);
304c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky    }
30515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
30615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
30715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  virtual ~DebugFrameOpCodeWriter() { }
30815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
30915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky protected:
31015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  int FactorDataOffset(int offset) const {
31115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    DCHECK_EQ(offset % kDataAlignmentFactor, 0);
31215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    return offset / kDataAlignmentFactor;
31315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
31415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
31515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  int FactorCodeOffset(int offset) const {
31615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    DCHECK_EQ(offset % kCodeAlignmentFactor, 0);
31715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky    return offset / kCodeAlignmentFactor;
31815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  }
31915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
320c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  bool enabled_;  // If disabled all writes are no-ops.
32115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  std::vector<uint8_t, Allocator> opcodes_;
32215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  int current_cfa_offset_;
32315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  int current_pc_;
32415c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  bool uses_dwarf3_features_;
32515c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
32615c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky private:
32715c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky  DISALLOW_COPY_AND_ASSIGN(DebugFrameOpCodeWriter);
32815c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky};
32915c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
33015c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky}  // namespace dwarf
33115c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky}  // namespace art
33215c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky
33315c1975f5fa5ae646ae87b57394bfdae1090a236David Srbecky#endif  // ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
334