1 /*
2 * Copyright (C) 2017 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 "slicer/common.h"
18 #include "slicer/code_ir.h"
19 #include "slicer/dex_bytecode.h"
20 #include "slicer/dex_format.h"
21 #include "slicer/dex_ir.h"
22 #include "slicer/dex_leb128.h"
23 #include "slicer/bytecode_encoder.h"
24 #include "slicer/debuginfo_encoder.h"
25 #include "slicer/tryblocks_encoder.h"
26
27 #include <assert.h>
28 #include <string.h>
29 #include <algorithm>
30 #include <cstdlib>
31 #include <type_traits>
32 #include <vector>
33
34 namespace lir {
35
Assemble()36 void CodeIr::Assemble() {
37 auto ir_code = ir_method->code;
38 SLICER_CHECK(ir_code != nullptr);
39
40 // new .dex bytecode
41 //
42 // NOTE: this must be done before the debug information and
43 // try/catch blocks since here is where we update the final offsets
44 //
45 BytecodeEncoder bytecode_encoder(instructions);
46 bytecode_encoder.Encode(ir_code, dex_ir);
47
48 // debug information
49 if (ir_code->debug_info != nullptr) {
50 DebugInfoEncoder dbginfo_encoder(instructions);
51 dbginfo_encoder.Encode(ir_method, dex_ir);
52 }
53
54 // try/catch blocks
55 TryBlocksEncoder try_blocks_encoder(instructions);
56 try_blocks_encoder.Encode(ir_code, dex_ir);
57 }
58
DissasembleTryBlocks(const ir::Code * ir_code)59 void CodeIr::DissasembleTryBlocks(const ir::Code* ir_code) {
60 int nextTryBlockId = 1;
61 for (const auto& tryBlock : ir_code->try_blocks) {
62 auto try_block_begin = Alloc<TryBlockBegin>();
63 try_block_begin->id = nextTryBlockId++;
64 try_block_begin->offset = tryBlock.start_addr;
65
66 auto try_block_end = Alloc<TryBlockEnd>();
67 try_block_end->try_begin = try_block_begin;
68 try_block_end->offset = tryBlock.start_addr + tryBlock.insn_count;
69
70 // parse the catch handlers
71 const dex::u1* ptr =
72 ir_code->catch_handlers.ptr<dex::u1>() + tryBlock.handler_off;
73 int catchCount = dex::ReadSLeb128(&ptr);
74
75 for (int catchIndex = 0; catchIndex < std::abs(catchCount); ++catchIndex) {
76 CatchHandler handler = {};
77
78 // type
79 dex::u4 type_index = dex::ReadULeb128(&ptr);
80 handler.ir_type = dex_ir->types_map[type_index];
81 SLICER_CHECK(handler.ir_type != nullptr);
82
83 // address
84 dex::u4 address = dex::ReadULeb128(&ptr);
85 handler.label = GetLabel(address);
86
87 try_block_end->handlers.push_back(handler);
88 }
89
90 // catch_all handler?
91 //
92 // NOTE: this is used to generate code for the "finally" blocks
93 // (see Java Virtual Machine Specification - 3.13 "Compiling finally")
94 //
95 if (catchCount < 1) {
96 dex::u4 address = dex::ReadULeb128(&ptr);
97 try_block_end->catch_all = GetLabel(address);
98 }
99
100 // we should have at least one handler
101 SLICER_CHECK(!try_block_end->handlers.empty() ||
102 try_block_end->catch_all != nullptr);
103
104 try_begins_.push_back(try_block_begin);
105 try_ends_.push_back(try_block_end);
106 }
107 }
108
DissasembleDebugInfo(const ir::DebugInfo * ir_debug_info)109 void CodeIr::DissasembleDebugInfo(const ir::DebugInfo* ir_debug_info) {
110 if (ir_debug_info == nullptr) {
111 return;
112 }
113
114 // debug info state machine registers
115 dex::u4 address = 0;
116 int line = ir_debug_info->line_start;
117 ir::String* source_file = ir_method->decl->parent->class_def->source_file;
118
119 // header
120 if (!ir_debug_info->param_names.empty()) {
121 auto dbg_header = Alloc<DbgInfoHeader>();
122 dbg_header->param_names = ir_debug_info->param_names;
123 dbg_header->offset = 0;
124 dbg_annotations_.push_back(dbg_header);
125 }
126
127 // initial source file
128 {
129 auto annotation = Alloc<DbgInfoAnnotation>(dex::DBG_SET_FILE);
130 annotation->offset = 0;
131 annotation->operands.push_back(Alloc<String>(
132 source_file, source_file ? source_file->orig_index : dex::kNoIndex));
133 dbg_annotations_.push_back(annotation);
134 }
135
136 // initial line number - redundant?
137 {
138 auto annotation = Alloc<DbgInfoAnnotation>(dex::DBG_ADVANCE_LINE);
139 annotation->offset = 0;
140 annotation->operands.push_back(Alloc<LineNumber>(line));
141 dbg_annotations_.push_back(annotation);
142 }
143
144 // debug info annotations
145 const dex::u1* ptr = ir_debug_info->data.ptr<dex::u1>();
146 dex::u1 opcode = 0;
147 while ((opcode = *ptr++) != dex::DBG_END_SEQUENCE) {
148 DbgInfoAnnotation* annotation = nullptr;
149
150 switch (opcode) {
151 case dex::DBG_ADVANCE_PC:
152 // addr_diff
153 address += dex::ReadULeb128(&ptr);
154 break;
155
156 case dex::DBG_ADVANCE_LINE:
157 // line_diff
158 line += dex::ReadSLeb128(&ptr);
159 SLICER_WEAK_CHECK(line > 0);
160 break;
161
162 case dex::DBG_START_LOCAL: {
163 annotation = Alloc<DbgInfoAnnotation>(opcode);
164
165 // register_num
166 annotation->operands.push_back(Alloc<VReg>(dex::ReadULeb128(&ptr)));
167
168 // name
169 dex::u4 name_index = dex::ReadULeb128(&ptr) - 1;
170 annotation->operands.push_back(GetString(name_index));
171
172 // type
173 dex::u4 type_index = dex::ReadULeb128(&ptr) - 1;
174 annotation->operands.push_back(GetType(type_index));
175 } break;
176
177 case dex::DBG_START_LOCAL_EXTENDED: {
178 annotation = Alloc<DbgInfoAnnotation>(opcode);
179
180 // register_num
181 annotation->operands.push_back(Alloc<VReg>(dex::ReadULeb128(&ptr)));
182
183 // name
184 dex::u4 name_index = dex::ReadULeb128(&ptr) - 1;
185 annotation->operands.push_back(GetString(name_index));
186
187 // type
188 dex::u4 type_index = dex::ReadULeb128(&ptr) - 1;
189 annotation->operands.push_back(GetType(type_index));
190
191 // signature
192 dex::u4 sig_index = dex::ReadULeb128(&ptr) - 1;
193 annotation->operands.push_back(GetString(sig_index));
194 } break;
195
196 case dex::DBG_END_LOCAL:
197 case dex::DBG_RESTART_LOCAL:
198 annotation = Alloc<DbgInfoAnnotation>(opcode);
199 // register_num
200 annotation->operands.push_back(Alloc<VReg>(dex::ReadULeb128(&ptr)));
201 break;
202
203 case dex::DBG_SET_PROLOGUE_END:
204 annotation = Alloc<DbgInfoAnnotation>(opcode);
205 break;
206
207 case dex::DBG_SET_EPILOGUE_BEGIN:
208 annotation = Alloc<DbgInfoAnnotation>(opcode);
209 break;
210
211 case dex::DBG_SET_FILE: {
212 annotation = Alloc<DbgInfoAnnotation>(opcode);
213
214 // source file name
215 dex::u4 name_index = dex::ReadULeb128(&ptr) - 1;
216 source_file = (name_index == dex::kNoIndex)
217 ? nullptr
218 : dex_ir->strings_map[name_index];
219 annotation->operands.push_back(Alloc<String>(source_file, name_index));
220 } break;
221
222 default: {
223 int adjusted_opcode = opcode - dex::DBG_FIRST_SPECIAL;
224 line += dex::DBG_LINE_BASE + (adjusted_opcode % dex::DBG_LINE_RANGE);
225 address += (adjusted_opcode / dex::DBG_LINE_RANGE);
226 SLICER_WEAK_CHECK(line > 0);
227 annotation = Alloc<DbgInfoAnnotation>(dex::DBG_ADVANCE_LINE);
228 annotation->operands.push_back(Alloc<LineNumber>(line));
229 } break;
230 }
231
232 if (annotation != nullptr) {
233 annotation->offset = address;
234 dbg_annotations_.push_back(annotation);
235 }
236 }
237 }
238
DissasembleBytecode(const ir::Code * ir_code)239 void CodeIr::DissasembleBytecode(const ir::Code* ir_code) {
240 const dex::u2* begin = ir_code->instructions.begin();
241 const dex::u2* end = ir_code->instructions.end();
242 const dex::u2* ptr = begin;
243
244 while (ptr < end) {
245 auto isize = dex::GetWidthFromBytecode(ptr);
246 SLICER_CHECK(isize > 0);
247
248 dex::u4 offset = ptr - begin;
249
250 Instruction* instr = nullptr;
251 switch (*ptr) {
252 case dex::kPackedSwitchSignature:
253 instr = DecodePackedSwitch(ptr, offset);
254 break;
255
256 case dex::kSparseSwitchSignature:
257 instr = DecodeSparseSwitch(ptr, offset);
258 break;
259
260 case dex::kArrayDataSignature:
261 instr = DecodeArrayData(ptr, offset);
262 break;
263
264 default:
265 instr = DecodeBytecode(ptr, offset);
266 break;
267 }
268
269 instr->offset = offset;
270 instructions.push_back(instr);
271 ptr += isize;
272 }
273 SLICER_CHECK(ptr == end);
274 }
275
FixupSwitches()276 void CodeIr::FixupSwitches() {
277 const dex::u2* begin = ir_method->code->instructions.begin();
278
279 // packed switches
280 for (auto& fixup : packed_switches_) {
281 FixupPackedSwitch(fixup.second.instr, fixup.second.base_offset,
282 begin + fixup.first);
283 }
284
285 // sparse switches
286 for (auto& fixup : sparse_switches_) {
287 FixupSparseSwitch(fixup.second.instr, fixup.second.base_offset,
288 begin + fixup.first);
289 }
290 }
291
292 // merge a set of extra instructions into the instruction list
293 template <class I_LIST, class E_LIST>
MergeInstructions(I_LIST & instructions,const E_LIST & extra)294 static void MergeInstructions(I_LIST& instructions, const E_LIST& extra) {
295
296 // the extra instructins must be sorted by offset
297 SLICER_CHECK(std::is_sorted(extra.begin(), extra.end(),
298 [](const Instruction* a, const Instruction* b) {
299 return a->offset < b->offset;
300 }));
301
302 auto instrIt = instructions.begin();
303 auto extraIt = extra.begin();
304
305 while (extraIt != extra.end()) {
306 if (instrIt == instructions.end() ||
307 (*extraIt)->offset == (*instrIt)->offset) {
308 instructions.insert(instrIt, *extraIt);
309 ++extraIt;
310 } else {
311 ++instrIt;
312 }
313 }
314 }
315
Dissasemble()316 void CodeIr::Dissasemble() {
317 nodes_.clear();
318 labels_.clear();
319
320 try_begins_.clear();
321 try_ends_.clear();
322 dbg_annotations_.clear();
323 packed_switches_.clear();
324 sparse_switches_.clear();
325
326 auto ir_code = ir_method->code;
327 if (ir_code == nullptr) {
328 return;
329 }
330
331 // decode the .dex bytecodes
332 DissasembleBytecode(ir_code);
333
334 // try/catch blocks
335 DissasembleTryBlocks(ir_code);
336
337 // debug information
338 DissasembleDebugInfo(ir_code->debug_info);
339
340 // fixup switches
341 FixupSwitches();
342
343 // assign label ids
344 std::vector<Label*> tmp_labels;
345 int nextLabelId = 1;
346 for (auto& label : labels_) {
347 label.second->id = nextLabelId++;
348 tmp_labels.push_back(label.second);
349 }
350
351 // merge the labels into the instructions stream
352 MergeInstructions(instructions, dbg_annotations_);
353 MergeInstructions(instructions, try_begins_);
354 MergeInstructions(instructions, tmp_labels);
355 MergeInstructions(instructions, try_ends_);
356 }
357
DecodePackedSwitch(const dex::u2 *,dex::u4 offset)358 PackedSwitchPayload* CodeIr::DecodePackedSwitch(const dex::u2* /*ptr*/,
359 dex::u4 offset) {
360 // actual decoding is delayed to FixupPackedSwitch()
361 // (since the label offsets are relative to the referring
362 // instruction, not the switch data)
363 SLICER_CHECK(offset % 2 == 0);
364 auto& instr = packed_switches_[offset].instr;
365 SLICER_CHECK(instr == nullptr);
366 instr = Alloc<PackedSwitchPayload>();
367 return instr;
368 }
369
FixupPackedSwitch(PackedSwitchPayload * instr,dex::u4 base_offset,const dex::u2 * ptr)370 void CodeIr::FixupPackedSwitch(PackedSwitchPayload* instr, dex::u4 base_offset,
371 const dex::u2* ptr) {
372 SLICER_CHECK(instr->targets.empty());
373
374 auto dex_packed_switch = reinterpret_cast<const dex::PackedSwitchPayload*>(ptr);
375 SLICER_CHECK(dex_packed_switch->ident == dex::kPackedSwitchSignature);
376
377 instr->first_key = dex_packed_switch->first_key;
378 for (dex::u2 i = 0; i < dex_packed_switch->size; ++i) {
379 instr->targets.push_back(
380 GetLabel(base_offset + dex_packed_switch->targets[i]));
381 }
382 }
383
DecodeSparseSwitch(const dex::u2 *,dex::u4 offset)384 SparseSwitchPayload* CodeIr::DecodeSparseSwitch(const dex::u2* /*ptr*/,
385 dex::u4 offset) {
386 // actual decoding is delayed to FixupSparseSwitch()
387 // (since the label offsets are relative to the referring
388 // instruction, not the switch data)
389 SLICER_CHECK(offset % 2 == 0);
390 auto& instr = sparse_switches_[offset].instr;
391 SLICER_CHECK(instr == nullptr);
392 instr = Alloc<SparseSwitchPayload>();
393 return instr;
394 }
395
FixupSparseSwitch(SparseSwitchPayload * instr,dex::u4 base_offset,const dex::u2 * ptr)396 void CodeIr::FixupSparseSwitch(SparseSwitchPayload* instr, dex::u4 base_offset,
397 const dex::u2* ptr) {
398 SLICER_CHECK(instr->switch_cases.empty());
399
400 auto dex_sparse_switch = reinterpret_cast<const dex::SparseSwitchPayload*>(ptr);
401 SLICER_CHECK(dex_sparse_switch->ident == dex::kSparseSwitchSignature);
402
403 auto& data = dex_sparse_switch->data;
404 auto& size = dex_sparse_switch->size;
405
406 for (dex::u2 i = 0; i < size; ++i) {
407 SparseSwitchPayload::SwitchCase switch_case = {};
408 switch_case.key = data[i];
409 switch_case.target = GetLabel(base_offset + data[i + size]);
410 instr->switch_cases.push_back(switch_case);
411 }
412 }
413
DecodeArrayData(const dex::u2 * ptr,dex::u4 offset)414 ArrayData* CodeIr::DecodeArrayData(const dex::u2* ptr, dex::u4 offset) {
415 auto dex_array_data = reinterpret_cast<const dex::ArrayData*>(ptr);
416 SLICER_CHECK(dex_array_data->ident == dex::kArrayDataSignature);
417 SLICER_CHECK(offset % 2 == 0);
418
419 auto instr = Alloc<ArrayData>();
420 instr->data = slicer::MemView(ptr, dex::GetWidthFromBytecode(ptr) * 2);
421 return instr;
422 }
423
GetRegA(const dex::Instruction & dex_instr)424 Operand* CodeIr::GetRegA(const dex::Instruction& dex_instr) {
425 auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode);
426 if ((verify_flags & dex::kVerifyRegAWide) != 0) {
427 return Alloc<VRegPair>(dex_instr.vA);
428 } else {
429 return Alloc<VReg>(dex_instr.vA);
430 }
431 }
432
GetRegB(const dex::Instruction & dex_instr)433 Operand* CodeIr::GetRegB(const dex::Instruction& dex_instr) {
434 auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode);
435 if ((verify_flags & dex::kVerifyRegBWide) != 0) {
436 return Alloc<VRegPair>(dex_instr.vB);
437 } else {
438 return Alloc<VReg>(dex_instr.vB);
439 }
440 }
441
GetRegC(const dex::Instruction & dex_instr)442 Operand* CodeIr::GetRegC(const dex::Instruction& dex_instr) {
443 auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode);
444 if ((verify_flags & dex::kVerifyRegCWide) != 0) {
445 return Alloc<VRegPair>(dex_instr.vC);
446 } else {
447 return Alloc<VReg>(dex_instr.vC);
448 }
449 }
450
DecodeBytecode(const dex::u2 * ptr,dex::u4 offset)451 Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) {
452 auto dex_instr = dex::DecodeInstruction(ptr);
453
454 auto instr = Alloc<Bytecode>();
455 instr->opcode = dex_instr.opcode;
456
457 auto index_type = dex::GetIndexTypeFromOpcode(dex_instr.opcode);
458
459 switch (dex::GetFormatFromOpcode(dex_instr.opcode)) {
460 case dex::k10x: // op
461 break;
462
463 case dex::k12x: // op vA, vB
464 case dex::k22x: // op vAA, vBBBB
465 case dex::k32x: // op vAAAA, vBBBB
466 instr->operands.push_back(GetRegA(dex_instr));
467 instr->operands.push_back(GetRegB(dex_instr));
468 break;
469
470 case dex::k11n: // op vA, #+B
471 case dex::k21s: // op vAA, #+BBBB
472 case dex::k31i: // op vAA, #+BBBBBBBB
473 instr->operands.push_back(GetRegA(dex_instr));
474 instr->operands.push_back(Alloc<Const32>(dex_instr.vB));
475 break;
476
477 case dex::k11x: // op vAA
478 instr->operands.push_back(GetRegA(dex_instr));
479 break;
480
481 case dex::k10t: // op +AA
482 case dex::k20t: // op +AAAA
483 case dex::k30t: // op +AAAAAAAA
484 {
485 auto label = GetLabel(offset + dex::s4(dex_instr.vA));
486 instr->operands.push_back(Alloc<CodeLocation>(label));
487 } break;
488
489 case dex::k21t: // op vAA, +BBBB
490 case dex::k31t: // op vAA, +BBBBBBBB
491 {
492 dex::u4 targetOffset = offset + dex::s4(dex_instr.vB);
493 instr->operands.push_back(GetRegA(dex_instr));
494 auto label = GetLabel(targetOffset);
495 instr->operands.push_back(Alloc<CodeLocation>(label));
496
497 if (dex_instr.opcode == dex::OP_PACKED_SWITCH) {
498 label->aligned = true;
499 dex::u4& base_offset = packed_switches_[targetOffset].base_offset;
500 SLICER_CHECK(base_offset == kInvalidOffset);
501 base_offset = offset;
502 } else if (dex_instr.opcode == dex::OP_SPARSE_SWITCH) {
503 label->aligned = true;
504 dex::u4& base_offset = sparse_switches_[targetOffset].base_offset;
505 SLICER_CHECK(base_offset == kInvalidOffset);
506 base_offset = offset;
507 } else if (dex_instr.opcode == dex::OP_FILL_ARRAY_DATA) {
508 label->aligned = true;
509 }
510 } break;
511
512 case dex::k23x: // op vAA, vBB, vCC
513 instr->operands.push_back(GetRegA(dex_instr));
514 instr->operands.push_back(GetRegB(dex_instr));
515 instr->operands.push_back(GetRegC(dex_instr));
516 break;
517
518 case dex::k22t: // op vA, vB, +CCCC
519 {
520 instr->operands.push_back(GetRegA(dex_instr));
521 instr->operands.push_back(GetRegB(dex_instr));
522 auto label = GetLabel(offset + dex::s4(dex_instr.vC));
523 instr->operands.push_back(Alloc<CodeLocation>(label));
524 } break;
525
526 case dex::k22b: // op vAA, vBB, #+CC
527 case dex::k22s: // op vA, vB, #+CCCC
528 instr->operands.push_back(GetRegA(dex_instr));
529 instr->operands.push_back(GetRegB(dex_instr));
530 instr->operands.push_back(Alloc<Const32>(dex_instr.vC));
531 break;
532
533 case dex::k22c: // op vA, vB, thing@CCCC
534 instr->operands.push_back(GetRegA(dex_instr));
535 instr->operands.push_back(GetRegB(dex_instr));
536 instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vC));
537 break;
538
539 case dex::k21c: // op vAA, thing@BBBB
540 case dex::k31c: // op vAA, string@BBBBBBBB
541 instr->operands.push_back(GetRegA(dex_instr));
542 instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
543 break;
544
545 case dex::k35c: // op {vC,vD,vE,vF,vG}, thing@BBBB
546 {
547 SLICER_CHECK(dex_instr.vA <= 5);
548 auto vreg_list = Alloc<VRegList>();
549 for (dex::u4 i = 0; i < dex_instr.vA; ++i) {
550 vreg_list->registers.push_back(dex_instr.arg[i]);
551 }
552 instr->operands.push_back(vreg_list);
553 instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
554 } break;
555
556 case dex::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
557 {
558 auto vreg_range = Alloc<VRegRange>(dex_instr.vC, dex_instr.vA);
559 instr->operands.push_back(vreg_range);
560 instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
561 } break;
562
563 case dex::k21h: // op vAA, #+BBBB0000[00000000]
564 switch (dex_instr.opcode) {
565 case dex::OP_CONST_HIGH16:
566 instr->operands.push_back(GetRegA(dex_instr));
567 instr->operands.push_back(Alloc<Const32>(dex_instr.vB << 16));
568 break;
569
570 case dex::OP_CONST_WIDE_HIGH16:
571 instr->operands.push_back(GetRegA(dex_instr));
572 instr->operands.push_back(Alloc<Const64>(dex::u8(dex_instr.vB) << 48));
573 break;
574
575 default:
576 SLICER_FATAL("Unexpected opcode 0x%02x", dex_instr.opcode);
577 }
578 break;
579
580 case dex::k51l: // op vAA, #+BBBBBBBBBBBBBBBB
581 instr->operands.push_back(GetRegA(dex_instr));
582 instr->operands.push_back(Alloc<Const64>(dex_instr.vB_wide));
583 break;
584
585 default:
586 SLICER_FATAL("Unexpected bytecode format (opcode 0x%02x)", dex_instr.opcode);
587 }
588
589 return instr;
590 }
591
592 // Get a indexed object (string, field, ...)
593 // (index must be valid != kNoIndex)
GetIndexedOperand(dex::InstructionIndexType index_type,dex::u4 index)594 IndexedOperand* CodeIr::GetIndexedOperand(dex::InstructionIndexType index_type,
595 dex::u4 index) {
596 SLICER_CHECK(index != dex::kNoIndex);
597 switch (index_type) {
598 case dex::kIndexStringRef:
599 return Alloc<String>(dex_ir->strings_map[index], index);
600
601 case dex::kIndexTypeRef:
602 return Alloc<Type>(dex_ir->types_map[index], index);
603
604 case dex::kIndexFieldRef:
605 return Alloc<Field>(dex_ir->fields_map[index], index);
606
607 case dex::kIndexMethodRef:
608 return Alloc<Method>(dex_ir->methods_map[index], index);
609
610 default:
611 SLICER_FATAL("Unexpected index type 0x%02x", index_type);
612 }
613 }
614
615 // Get a type based on its index (potentially kNoIndex)
GetType(dex::u4 index)616 Type* CodeIr::GetType(dex::u4 index) {
617 auto ir_type = (index == dex::kNoIndex) ? nullptr : dex_ir->types_map[index];
618 return Alloc<Type>(ir_type, index);
619 }
620
621 // Get a string based on its index (potentially kNoIndex)
GetString(dex::u4 index)622 String* CodeIr::GetString(dex::u4 index) {
623 auto ir_string = (index == dex::kNoIndex) ? nullptr : dex_ir->strings_map[index];
624 return Alloc<String>(ir_string, index);
625 }
626
627 // Get en existing, or new label for a particular offset
GetLabel(dex::u4 offset)628 Label* CodeIr::GetLabel(dex::u4 offset) {
629 auto& p = labels_[offset];
630 if (p == nullptr) {
631 p = Alloc<Label>(offset);
632 }
633 ++p->refCount;
634 return p;
635 }
636
637 } // namespace lir
638