1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "dex_to_dex_decompiler.h"
18
19#include <android-base/logging.h>
20
21#include "base/macros.h"
22#include "base/mutex.h"
23#include "dex/bytecode_utils.h"
24#include "dex/code_item_accessors-inl.h"
25#include "dex/dex_file-inl.h"
26#include "dex/dex_instruction-inl.h"
27#include "quicken_info.h"
28
29namespace art {
30namespace optimizer {
31
32class DexDecompiler {
33 public:
34  DexDecompiler(const DexFile& dex_file,
35                const DexFile::CodeItem& code_item,
36                const ArrayRef<const uint8_t>& quickened_info,
37                bool decompile_return_instruction)
38    : code_item_accessor_(dex_file, &code_item),
39      quicken_info_(quickened_info),
40      decompile_return_instruction_(decompile_return_instruction) {}
41
42  bool Decompile();
43
44 private:
45  void DecompileInstanceFieldAccess(Instruction* inst, Instruction::Code new_opcode) {
46    uint16_t index = NextIndex();
47    inst->SetOpcode(new_opcode);
48    inst->SetVRegC_22c(index);
49  }
50
51  void DecompileInvokeVirtual(Instruction* inst, Instruction::Code new_opcode, bool is_range) {
52    const uint16_t index = NextIndex();
53    inst->SetOpcode(new_opcode);
54    if (is_range) {
55      inst->SetVRegB_3rc(index);
56    } else {
57      inst->SetVRegB_35c(index);
58    }
59  }
60
61  void DecompileNop(Instruction* inst) {
62    const uint16_t reference_index = NextIndex();
63    if (reference_index == DexFile::kDexNoIndex16) {
64      // This means it was a normal nop and not a check-cast.
65      return;
66    }
67    const uint16_t type_index = NextIndex();
68    inst->SetOpcode(Instruction::CHECK_CAST);
69    inst->SetVRegA_21c(reference_index);
70    inst->SetVRegB_21c(type_index);
71  }
72
73  uint16_t NextIndex() {
74    DCHECK_LT(quicken_index_, quicken_info_.NumIndices());
75    const uint16_t ret = quicken_info_.GetData(quicken_index_);
76    quicken_index_++;
77    return ret;
78  }
79
80  const CodeItemInstructionAccessor code_item_accessor_;
81  const QuickenInfoTable quicken_info_;
82  const bool decompile_return_instruction_;
83
84  size_t quicken_index_ = 0u;
85
86  DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
87};
88
89bool DexDecompiler::Decompile() {
90  // We need to iterate over the code item, and not over the quickening data,
91  // because the RETURN_VOID quickening is not encoded in the quickening data. Because
92  // unquickening is a rare need and not performance sensitive, it is not worth the
93  // added storage to also add the RETURN_VOID quickening in the quickened data.
94  for (const DexInstructionPcPair& pair : code_item_accessor_) {
95    Instruction* inst = const_cast<Instruction*>(&pair.Inst());
96
97    switch (inst->Opcode()) {
98      case Instruction::RETURN_VOID_NO_BARRIER:
99        if (decompile_return_instruction_) {
100          inst->SetOpcode(Instruction::RETURN_VOID);
101        }
102        break;
103
104      case Instruction::NOP:
105        if (quicken_info_.NumIndices() > 0) {
106          // Only try to decompile NOP if there are more than 0 indices. Not having
107          // any index happens when we unquicken a code item that only has
108          // RETURN_VOID_NO_BARRIER as quickened instruction.
109          DecompileNop(inst);
110        }
111        break;
112
113      case Instruction::IGET_QUICK:
114        DecompileInstanceFieldAccess(inst, Instruction::IGET);
115        break;
116
117      case Instruction::IGET_WIDE_QUICK:
118        DecompileInstanceFieldAccess(inst, Instruction::IGET_WIDE);
119        break;
120
121      case Instruction::IGET_OBJECT_QUICK:
122        DecompileInstanceFieldAccess(inst, Instruction::IGET_OBJECT);
123        break;
124
125      case Instruction::IGET_BOOLEAN_QUICK:
126        DecompileInstanceFieldAccess(inst, Instruction::IGET_BOOLEAN);
127        break;
128
129      case Instruction::IGET_BYTE_QUICK:
130        DecompileInstanceFieldAccess(inst, Instruction::IGET_BYTE);
131        break;
132
133      case Instruction::IGET_CHAR_QUICK:
134        DecompileInstanceFieldAccess(inst, Instruction::IGET_CHAR);
135        break;
136
137      case Instruction::IGET_SHORT_QUICK:
138        DecompileInstanceFieldAccess(inst, Instruction::IGET_SHORT);
139        break;
140
141      case Instruction::IPUT_QUICK:
142        DecompileInstanceFieldAccess(inst, Instruction::IPUT);
143        break;
144
145      case Instruction::IPUT_BOOLEAN_QUICK:
146        DecompileInstanceFieldAccess(inst, Instruction::IPUT_BOOLEAN);
147        break;
148
149      case Instruction::IPUT_BYTE_QUICK:
150        DecompileInstanceFieldAccess(inst, Instruction::IPUT_BYTE);
151        break;
152
153      case Instruction::IPUT_CHAR_QUICK:
154        DecompileInstanceFieldAccess(inst, Instruction::IPUT_CHAR);
155        break;
156
157      case Instruction::IPUT_SHORT_QUICK:
158        DecompileInstanceFieldAccess(inst, Instruction::IPUT_SHORT);
159        break;
160
161      case Instruction::IPUT_WIDE_QUICK:
162        DecompileInstanceFieldAccess(inst, Instruction::IPUT_WIDE);
163        break;
164
165      case Instruction::IPUT_OBJECT_QUICK:
166        DecompileInstanceFieldAccess(inst, Instruction::IPUT_OBJECT);
167        break;
168
169      case Instruction::INVOKE_VIRTUAL_QUICK:
170        DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL, false);
171        break;
172
173      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
174        DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL_RANGE, true);
175        break;
176
177      default:
178        break;
179    }
180  }
181
182  if (quicken_index_ != quicken_info_.NumIndices()) {
183    if (quicken_index_ == 0) {
184      LOG(WARNING) << "Failed to use any value in quickening info,"
185                   << " potentially due to duplicate methods.";
186    } else {
187      LOG(FATAL) << "Failed to use all values in quickening info."
188                 << " Actual: " << std::hex << quicken_index_
189                 << " Expected: " << quicken_info_.NumIndices();
190      return false;
191    }
192  }
193
194  return true;
195}
196
197bool ArtDecompileDEX(const DexFile& dex_file,
198                     const DexFile::CodeItem& code_item,
199                     const ArrayRef<const uint8_t>& quickened_info,
200                     bool decompile_return_instruction) {
201  if (quickened_info.size() == 0 && !decompile_return_instruction) {
202    return true;
203  }
204  DexDecompiler decompiler(dex_file, code_item, quickened_info, decompile_return_instruction);
205  return decompiler.Decompile();
206}
207
208}  // namespace optimizer
209}  // namespace art
210