• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/bytecode_encoder.h"
18 #include "slicer/common.h"
19 #include "slicer/chronometer.h"
20 
21 #include <assert.h>
22 
23 namespace lir {
24 
25 // Pack a 16bit word: 00AA
Pack_Z_8(dex::u4 a)26 static dex::u2 Pack_Z_8(dex::u4 a) {
27   dex::u2 fa = (a & 0xff);
28   SLICER_CHECK(fa == a);
29   return fa;
30 }
31 
32 // Pack a 16bit word: AABB
Pack_8_8(dex::u4 a,dex::u4 b)33 static dex::u2 Pack_8_8(dex::u4 a, dex::u4 b) {
34   dex::u2 fa = (a & 0xff);
35   SLICER_CHECK(fa == a);
36   dex::u2 fb = (b & 0xff);
37   SLICER_CHECK(fb == b);
38   return (fa << 8) | fb;
39 }
40 
41 // Pack a 16bit word: ABCC
Pack_4_4_8(dex::u4 a,dex::u4 b,dex::u4 c)42 static dex::u2 Pack_4_4_8(dex::u4 a, dex::u4 b, dex::u4 c) {
43   dex::u2 fa = (a & 0xf);
44   SLICER_CHECK(fa == a);
45   dex::u2 fb = (b & 0xf);
46   SLICER_CHECK(fb == b);
47   dex::u2 fc = (c & 0xff);
48   SLICER_CHECK(fc == c);
49   return (fa << 12) | (fb << 8) | fc;
50 }
51 
52 // Pack a 16bit word: ABCD
Pack_4_4_4_4(dex::u4 a,dex::u4 b,dex::u4 c,dex::u4 d)53 static dex::u2 Pack_4_4_4_4(dex::u4 a, dex::u4 b, dex::u4 c, dex::u4 d) {
54   dex::u2 fa = (a & 0xf);
55   SLICER_CHECK(fa == a);
56   dex::u2 fb = (b & 0xf);
57   SLICER_CHECK(fb == b);
58   dex::u2 fc = (c & 0xf);
59   SLICER_CHECK(fc == c);
60   dex::u2 fd = (d & 0xf);
61   SLICER_CHECK(fd == d);
62   return (fa << 12) | (fb << 8) | (fc << 4) | fd;
63 }
64 
65 // Pack a 16bit word: AAAA
Pack_16(dex::u4 a)66 static dex::u2 Pack_16(dex::u4 a) {
67   dex::u2 fa = (a & 0xffff);
68   SLICER_CHECK(fa == a);
69   return fa;
70 }
71 
72 // Trim a 4bit signed integer, making sure we're not discarding significant bits
Trim_S0(dex::u4 value)73 static dex::u4 Trim_S0(dex::u4 value) {
74   dex::u4 trim = value & 0xf;
75   SLICER_CHECK(dex::u4(dex::s4(trim << 28) >> 28) == value);
76   return trim;
77 }
78 
79 // Trim a 8bit signed integer, making sure we're not discarding significant bits
Trim_S1(dex::u4 value)80 static dex::u4 Trim_S1(dex::u4 value) {
81   dex::u4 trim = value & 0xff;
82   SLICER_CHECK(dex::u4(dex::s4(trim << 24) >> 24) == value);
83   return trim;
84 }
85 
86 // Trim a 16bit signed integer, making sure we're not discarding significant bits
Trim_S2(dex::u4 value)87 static dex::u4 Trim_S2(dex::u4 value) {
88   dex::u4 trim = value & 0xffff;
89   SLICER_CHECK(dex::u4(dex::s4(trim << 16) >> 16) == value);
90   return trim;
91 }
92 
93 // Returns a register operand, checking the match between format and type
94 // (register fields can encode either a single 32bit vreg or a wide 64bit vreg pair)
GetRegA(const Bytecode * bytecode,int index)95 static dex::u4 GetRegA(const Bytecode* bytecode, int index) {
96   auto verify_flags = dex::GetVerifyFlagsFromOpcode(bytecode->opcode);
97   return (verify_flags & dex::kVerifyRegAWide) != 0
98              ? bytecode->CastOperand<VRegPair>(index)->base_reg
99              : bytecode->CastOperand<VReg>(index)->reg;
100 }
101 
102 // Returns a register operand, checking the match between format and type
103 // (register fields can encode either a single 32bit vreg or a wide 64bit vreg pair)
GetRegB(const Bytecode * bytecode,int index)104 static dex::u4 GetRegB(const Bytecode* bytecode, int index) {
105   auto verify_flags = dex::GetVerifyFlagsFromOpcode(bytecode->opcode);
106   return (verify_flags & dex::kVerifyRegBWide) != 0
107              ? bytecode->CastOperand<VRegPair>(index)->base_reg
108              : bytecode->CastOperand<VReg>(index)->reg;
109 }
110 
111 // Returns a register operand, checking the match between format and type
112 // (register fields can encode either a single 32bit vreg or a wide 64bit vreg pair)
GetRegC(const Bytecode * bytecode,int index)113 static dex::u4 GetRegC(const Bytecode* bytecode, int index) {
114   auto verify_flags = dex::GetVerifyFlagsFromOpcode(bytecode->opcode);
115   return (verify_flags & dex::kVerifyRegCWide) != 0
116              ? bytecode->CastOperand<VRegPair>(index)->base_reg
117              : bytecode->CastOperand<VReg>(index)->reg;
118 }
119 
120 // Encode one instruction into a .dex bytecode
121 //
122 // NOTE: the formats and the operand notation is documented here:
123 //   https://source.android.com/devices/tech/dalvik/instruction-formats.html
124 //
Visit(Bytecode * bytecode)125 bool BytecodeEncoder::Visit(Bytecode* bytecode) {
126   bytecode->offset = offset_;
127   dex::Opcode opcode = bytecode->opcode;
128 
129   // Unconditionally replace short (8bit) branches with
130   // medium-range (16bit) branches. This should cover 99.999% of
131   // the cases and it avoids a more complex branch length handling.
132   if (opcode == dex::OP_GOTO) {
133     opcode = dex::OP_GOTO_16;
134   }
135 
136   auto buff_offset = bytecode_.size();
137   auto format = dex::GetFormatFromOpcode(opcode);
138 
139   switch (format) {
140     case dex::k10x:  // op
141     {
142       SLICER_CHECK(bytecode->operands.size() == 0);
143       bytecode_.Push<dex::u2>(Pack_Z_8(opcode));
144     } break;
145 
146     case dex::k12x:  // op vA, vB
147     {
148       SLICER_CHECK(bytecode->operands.size() == 2);
149       dex::u4 vA = GetRegA(bytecode, 0);
150       dex::u4 vB = GetRegB(bytecode, 1);
151       bytecode_.Push<dex::u2>(Pack_4_4_8(vB, vA, opcode));
152     } break;
153 
154     case dex::k22x:  // op vAA, vBBBB
155     {
156       SLICER_CHECK(bytecode->operands.size() == 2);
157       dex::u4 vA = GetRegA(bytecode, 0);
158       dex::u4 vB = GetRegB(bytecode, 1);
159       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
160       bytecode_.Push<dex::u2>(Pack_16(vB));
161     } break;
162 
163     case dex::k32x:  // op vAAAA, vBBBB
164     {
165       SLICER_CHECK(bytecode->operands.size() == 2);
166       dex::u4 vA = GetRegA(bytecode, 0);
167       dex::u4 vB = GetRegB(bytecode, 1);
168       bytecode_.Push<dex::u2>(Pack_Z_8(opcode));
169       bytecode_.Push<dex::u2>(Pack_16(vA));
170       bytecode_.Push<dex::u2>(Pack_16(vB));
171     } break;
172 
173     case dex::k11n:  // op vA, #+B
174     {
175       SLICER_CHECK(bytecode->operands.size() == 2);
176       dex::u4 vA = GetRegA(bytecode, 0);
177       dex::u4 B = Trim_S0(bytecode->CastOperand<Const32>(1)->u.u4_value);
178       bytecode_.Push<dex::u2>(Pack_4_4_8(B, vA, opcode));
179     } break;
180 
181     case dex::k21s:  // op vAA, #+BBBB
182     {
183       SLICER_CHECK(bytecode->operands.size() == 2);
184       dex::u4 vA = GetRegA(bytecode, 0);
185       dex::u4 B = Trim_S2(bytecode->CastOperand<Const32>(1)->u.u4_value);
186       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
187       bytecode_.Push<dex::u2>(Pack_16(B));
188     } break;
189 
190     case dex::k11x:  // op vAA
191     {
192       SLICER_CHECK(bytecode->operands.size() == 1);
193       dex::u4 vA = GetRegA(bytecode, 0);
194       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
195     } break;
196 
197     case dex::k31i:  // op vAA, #+BBBBBBBB
198     {
199       SLICER_CHECK(bytecode->operands.size() == 2);
200       dex::u4 vA = GetRegA(bytecode, 0);
201       dex::u4 B = bytecode->CastOperand<Const32>(1)->u.u4_value;
202       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
203       bytecode_.Push<dex::u2>(Pack_16(B & 0xffff));
204       bytecode_.Push<dex::u2>(Pack_16(B >> 16));
205     } break;
206 
207     case dex::k20t:  // op +AAAA
208     {
209       SLICER_CHECK(bytecode->operands.size() == 1);
210       auto label = bytecode->CastOperand<CodeLocation>(0)->label;
211       dex::u4 A = 0;
212       if (label->offset != kInvalidOffset) {
213         assert(label->offset <= offset_);
214         A = label->offset - offset_;
215         SLICER_CHECK(A != 0);
216         SLICER_CHECK((A >> 16) == 0xffff);  // TODO: out of range!
217       } else {
218         fixups_.push_back(LabelFixup(offset_, label, true));
219       }
220       bytecode_.Push<dex::u2>(Pack_Z_8(opcode));
221       bytecode_.Push<dex::u2>(Pack_16(A & 0xffff));
222     } break;
223 
224     case dex::k30t:  // op +AAAAAAAA
225     {
226       SLICER_CHECK(bytecode->operands.size() == 1);
227       auto label = bytecode->CastOperand<CodeLocation>(0)->label;
228       dex::u4 A = 0;
229       if (label->offset != kInvalidOffset) {
230         // NOTE: goto/32 can branch to itself
231         assert(label->offset <= offset_);
232         A = label->offset - offset_;
233       } else {
234         fixups_.push_back(LabelFixup(offset_, label, false));
235       }
236       bytecode_.Push<dex::u2>(Pack_Z_8(opcode));
237       bytecode_.Push<dex::u2>(Pack_16(A & 0xffff));
238       bytecode_.Push<dex::u2>(Pack_16(A >> 16));
239     } break;
240 
241     case dex::k21t:  // op vAA, +BBBB
242     {
243       SLICER_CHECK(bytecode->operands.size() == 2);
244       dex::u4 vA = GetRegA(bytecode, 0);
245       auto label = bytecode->CastOperand<CodeLocation>(1)->label;
246       dex::u4 B = 0;
247       if (label->offset != kInvalidOffset) {
248         assert(label->offset <= offset_);
249         B = label->offset - offset_;
250         SLICER_CHECK(B != 0);
251         SLICER_CHECK((B >> 16) == 0xffff);  // TODO: out of range!
252       } else {
253         fixups_.push_back(LabelFixup(offset_, label, true));
254       }
255       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
256       bytecode_.Push<dex::u2>(Pack_16(B & 0xffff));
257     } break;
258 
259     case dex::k22t:  // op vA, vB, +CCCC
260     {
261       SLICER_CHECK(bytecode->operands.size() == 3);
262       dex::u4 vA = GetRegA(bytecode, 0);
263       dex::u4 vB = GetRegB(bytecode, 1);
264       auto label = bytecode->CastOperand<CodeLocation>(2)->label;
265       dex::u4 C = 0;
266       if (label->offset != kInvalidOffset) {
267         assert(label->offset <= offset_);
268         C = label->offset - offset_;
269         SLICER_CHECK(C != 0);
270         SLICER_CHECK((C >> 16) == 0xffff);  // TODO: out of range!
271       } else {
272         fixups_.push_back(LabelFixup(offset_, label, true));
273       }
274       bytecode_.Push<dex::u2>(Pack_4_4_8(vB, vA, opcode));
275       bytecode_.Push<dex::u2>(Pack_16(C & 0xffff));
276     } break;
277 
278     case dex::k31t:  // op vAA, +BBBBBBBB
279     {
280       SLICER_CHECK(bytecode->operands.size() == 2);
281       dex::u4 vA = GetRegA(bytecode, 0);
282       auto label = bytecode->CastOperand<CodeLocation>(1)->label;
283       dex::u4 B = 0;
284       if (label->offset != kInvalidOffset) {
285         assert(label->offset <= offset_);
286         B = label->offset - offset_;
287         SLICER_CHECK(B != 0);
288       } else {
289         fixups_.push_back(LabelFixup(offset_, label, false));
290       }
291       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
292       bytecode_.Push<dex::u2>(Pack_16(B & 0xffff));
293       bytecode_.Push<dex::u2>(Pack_16(B >> 16));
294     } break;
295 
296     case dex::k23x:  // op vAA, vBB, vCC
297     {
298       SLICER_CHECK(bytecode->operands.size() == 3);
299       dex::u4 vA = GetRegA(bytecode, 0);
300       dex::u4 vB = GetRegB(bytecode, 1);
301       dex::u4 vC = GetRegC(bytecode, 2);
302       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
303       bytecode_.Push<dex::u2>(Pack_8_8(vC, vB));
304     } break;
305 
306     case dex::k22b:  // op vAA, vBB, #+CC
307     {
308       SLICER_CHECK(bytecode->operands.size() == 3);
309       dex::u4 vA = GetRegA(bytecode, 0);
310       dex::u4 vB = GetRegB(bytecode, 1);
311       dex::u4 C = Trim_S1(bytecode->CastOperand<Const32>(2)->u.u4_value);
312       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
313       bytecode_.Push<dex::u2>(Pack_8_8(C, vB));
314     } break;
315 
316     case dex::k22s:  // op vA, vB, #+CCCC
317     {
318       SLICER_CHECK(bytecode->operands.size() == 3);
319       dex::u4 vA = GetRegA(bytecode, 0);
320       dex::u4 vB = GetRegB(bytecode, 1);
321       dex::u4 C = Trim_S2(bytecode->CastOperand<Const32>(2)->u.u4_value);
322       bytecode_.Push<dex::u2>(Pack_4_4_8(vB, vA, opcode));
323       bytecode_.Push<dex::u2>(Pack_16(C));
324     } break;
325 
326     case dex::k22c:  // op vA, vB, thing@CCCC
327     {
328       SLICER_CHECK(bytecode->operands.size() == 3);
329       dex::u4 vA = GetRegA(bytecode, 0);
330       dex::u4 vB = GetRegB(bytecode, 1);
331       dex::u4 C = bytecode->CastOperand<IndexedOperand>(2)->index;
332       bytecode_.Push<dex::u2>(Pack_4_4_8(vB, vA, opcode));
333       bytecode_.Push<dex::u2>(Pack_16(C));
334     } break;
335 
336     case dex::k21c:  // op vAA, thing@BBBB
337     {
338       SLICER_CHECK(bytecode->operands.size() == 2);
339       dex::u4 vA = GetRegA(bytecode, 0);
340       dex::u4 B = bytecode->CastOperand<IndexedOperand>(1)->index;
341       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
342       bytecode_.Push<dex::u2>(Pack_16(B));
343     } break;
344 
345     case dex::k31c:  // op vAA, string@BBBBBBBB
346     {
347       SLICER_CHECK(bytecode->operands.size() == 2);
348       dex::u4 vA = GetRegA(bytecode, 0);
349       dex::u4 B = bytecode->CastOperand<IndexedOperand>(1)->index;
350       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
351       bytecode_.Push<dex::u2>(Pack_16(B & 0xffff));
352       bytecode_.Push<dex::u2>(Pack_16(B >> 16));
353     } break;
354 
355     case dex::k35c:  // op {vC,vD,vE,vF,vG}, thing@BBBB
356     {
357       SLICER_CHECK(bytecode->operands.size() == 2);
358       const auto& regs = bytecode->CastOperand<VRegList>(0)->registers;
359       dex::u4 B = bytecode->CastOperand<IndexedOperand>(1)->index;
360       dex::u4 A = regs.size();
361       dex::u4 C = (A > 0) ? regs[0] : 0;
362       dex::u4 D = (A > 1) ? regs[1] : 0;
363       dex::u4 E = (A > 2) ? regs[2] : 0;
364       dex::u4 F = (A > 3) ? regs[3] : 0;
365       dex::u4 G = (A > 4) ? regs[4] : 0;
366       bytecode_.Push<dex::u2>(Pack_4_4_8(A, G, opcode));
367       bytecode_.Push<dex::u2>(Pack_16(B));
368       bytecode_.Push<dex::u2>(Pack_4_4_4_4(F, E, D, C));
369 
370       // keep track of the outs_count
371       if ((dex::GetFlagsFromOpcode(opcode) & dex::kInvoke) != 0) {
372         outs_count_ = std::max(outs_count_, A);
373       }
374     } break;
375 
376     case dex::k3rc:  // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
377     {
378       SLICER_CHECK(bytecode->operands.size() == 2);
379       auto vreg_range = bytecode->CastOperand<VRegRange>(0);
380       dex::u4 A = vreg_range->count;
381       dex::u4 B = bytecode->CastOperand<IndexedOperand>(1)->index;
382       dex::u4 C = vreg_range->base_reg;
383       bytecode_.Push<dex::u2>(Pack_8_8(A, opcode));
384       bytecode_.Push<dex::u2>(Pack_16(B));
385       bytecode_.Push<dex::u2>(Pack_16(C));
386 
387       // keep track of the outs_count
388       if ((dex::GetFlagsFromOpcode(opcode) & dex::kInvoke) != 0) {
389         outs_count_ = std::max(outs_count_, A);
390       }
391     } break;
392 
393     case dex::k51l:  // op vAA, #+BBBBBBBBBBBBBBBB
394     {
395       SLICER_CHECK(bytecode->operands.size() == 2);
396       dex::u4 vA = GetRegA(bytecode, 0);
397       dex::u8 B = bytecode->CastOperand<Const64>(1)->u.u8_value;
398       bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
399       bytecode_.Push<dex::u2>(Pack_16((B >> 0) & 0xffff));
400       bytecode_.Push<dex::u2>(Pack_16((B >> 16) & 0xffff));
401       bytecode_.Push<dex::u2>(Pack_16((B >> 32) & 0xffff));
402       bytecode_.Push<dex::u2>(Pack_16((B >> 48) & 0xffff));
403     } break;
404 
405     case dex::k21h:  // op vAA, #+BBBB0000[00000000]
406       SLICER_CHECK(bytecode->operands.size() == 2);
407       switch (opcode) {
408         case dex::OP_CONST_HIGH16: {
409           dex::u4 vA = GetRegA(bytecode, 0);
410           dex::u4 B = bytecode->CastOperand<Const32>(1)->u.u4_value >> 16;
411           bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
412           bytecode_.Push<dex::u2>(Pack_16(B));
413         } break;
414 
415         case dex::OP_CONST_WIDE_HIGH16: {
416           dex::u4 vA = GetRegA(bytecode, 0);
417           dex::u4 B = bytecode->CastOperand<Const64>(1)->u.u8_value >> 48;
418           bytecode_.Push<dex::u2>(Pack_8_8(vA, opcode));
419           bytecode_.Push<dex::u2>(Pack_16(B));
420         } break;
421 
422         default:
423           SLICER_FATAL("Unexpected fmt21h opcode: 0x%02x", opcode);
424       }
425       break;
426 
427     default:
428       SLICER_FATAL("Unexpected format: 0x%02x", format);
429   }
430 
431   SLICER_CHECK(bytecode_.size() - buff_offset == 2 * GetWidthFromFormat(format));
432   offset_ += GetWidthFromFormat(format);
433   return true;
434 }
435 
Visit(PackedSwitchPayload * packed_switch)436 bool BytecodeEncoder::Visit(PackedSwitchPayload* packed_switch) {
437   SLICER_CHECK(offset_ % 2 == 0);
438 
439   // keep track of the switches
440   packed_switch->offset = offset_;
441   auto& instr = packed_switches_[offset_];
442   SLICER_CHECK(instr == nullptr);
443   instr = packed_switch;
444 
445   // we're going to fix up the offsets in a later pass
446   auto orig_size = bytecode_.size();
447   bytecode_.Push<dex::u2>(dex::kPackedSwitchSignature);
448   bytecode_.Push<dex::u2>(Pack_16(packed_switch->targets.size()));
449   bytecode_.Push<dex::s4>(packed_switch->first_key);
450   for (size_t i = 0; i < packed_switch->targets.size(); ++i) {
451     bytecode_.Push<dex::u4>(0);
452   }
453 
454   // offset is in 16bit units, not bytes
455   offset_ += (bytecode_.size() - orig_size) / 2;
456 
457   return true;
458 }
459 
Visit(SparseSwitchPayload * sparse_switch)460 bool BytecodeEncoder::Visit(SparseSwitchPayload* sparse_switch) {
461   SLICER_CHECK(offset_ % 2 == 0);
462 
463   // keep track of the switches
464   sparse_switch->offset = offset_;
465   auto& instr = sparse_switches_[offset_];
466   SLICER_CHECK(instr == nullptr);
467   instr = sparse_switch;
468 
469   // we're going to fix up the offsets in a later pass
470   auto orig_size = bytecode_.size();
471   bytecode_.Push<dex::u2>(dex::kSparseSwitchSignature);
472   bytecode_.Push<dex::u2>(Pack_16(sparse_switch->switch_cases.size()));
473   for (const auto& switch_case : sparse_switch->switch_cases) {
474     bytecode_.Push<dex::s4>(switch_case.key);
475   }
476   for (size_t i = 0; i < sparse_switch->switch_cases.size(); ++i) {
477     bytecode_.Push<dex::u4>(0);
478   }
479   offset_ += (bytecode_.size() - orig_size) / 2;
480 
481   return true;
482 }
483 
Visit(ArrayData * array_data)484 bool BytecodeEncoder::Visit(ArrayData* array_data) {
485   SLICER_CHECK(offset_ % 2 == 0);
486 
487   array_data->offset = offset_;
488   auto orig_size = bytecode_.size();
489   // kArrayDataSignature is already included by array_data->data
490   // (no need to emit here)
491   bytecode_.Push(array_data->data);
492   offset_ += (bytecode_.size() - orig_size) / 2;
493   return true;
494 }
495 
Visit(Label * label)496 bool BytecodeEncoder::Visit(Label* label) {
497   // aligned label?
498   if (label->aligned && offset_ % 2 == 1) {
499     bytecode_.Push<dex::u2>(dex::OP_NOP);
500     ++offset_;
501   }
502 
503   label->offset = offset_;
504   return true;
505 }
506 
Visit(DbgInfoHeader * dbg_header)507 bool BytecodeEncoder::Visit(DbgInfoHeader* dbg_header) {
508   dbg_header->offset = offset_;
509   return true;
510 }
511 
Visit(DbgInfoAnnotation * dbg_annotation)512 bool BytecodeEncoder::Visit(DbgInfoAnnotation* dbg_annotation) {
513   dbg_annotation->offset = offset_;
514   return true;
515 }
516 
Visit(TryBlockBegin * try_begin)517 bool BytecodeEncoder::Visit(TryBlockBegin* try_begin) {
518   try_begin->offset = offset_;
519   return true;
520 }
521 
Visit(TryBlockEnd * try_end)522 bool BytecodeEncoder::Visit(TryBlockEnd* try_end) {
523   try_end->offset = offset_;
524   return true;
525 }
526 
FixupSwitchOffsets()527 void BytecodeEncoder::FixupSwitchOffsets() {
528   dex::u2* const begin = bytecode_.ptr<dex::u2>(0);
529   dex::u2* const end = begin + bytecode_.size() / 2;
530   dex::u2* ptr = begin;
531   while (ptr < end) {
532     const auto opcode = dex::OpcodeFromBytecode(*ptr);
533     const auto offset = ptr - begin;
534     if (opcode == dex::OP_PACKED_SWITCH) {
535       auto dex_instr = dex::DecodeInstruction(ptr);
536       FixupPackedSwitch(offset, offset + dex::s4(dex_instr.vB));
537     } else if (opcode == dex::OP_SPARSE_SWITCH) {
538       auto dex_instr = dex::DecodeInstruction(ptr);
539       FixupSparseSwitch(offset, offset + dex::s4(dex_instr.vB));
540     }
541     auto isize = dex::GetWidthFromBytecode(ptr);
542     SLICER_CHECK(isize > 0);
543     ptr += isize;
544   }
545   SLICER_CHECK(ptr == end);
546 }
547 
FixupPackedSwitch(dex::u4 base_offset,dex::u4 payload_offset)548 void BytecodeEncoder::FixupPackedSwitch(dex::u4 base_offset,
549                                         dex::u4 payload_offset) {
550   auto instr = packed_switches_[payload_offset];
551   SLICER_CHECK(instr != nullptr);
552 
553   auto payload = bytecode_.ptr<dex::PackedSwitchPayload>(payload_offset * 2);
554   SLICER_CHECK(payload->ident == dex::kPackedSwitchSignature);
555   SLICER_CHECK(reinterpret_cast<dex::u1*>(payload->targets + payload->size) <=
556         bytecode_.data() + bytecode_.size());
557 
558   for (int i = 0; i < payload->size; ++i) {
559     auto label = instr->targets[i];
560     assert(label->offset != kInvalidOffset);
561     payload->targets[i] = label->offset - base_offset;
562   }
563 }
564 
FixupSparseSwitch(dex::u4 base_offset,dex::u4 payload_offset)565 void BytecodeEncoder::FixupSparseSwitch(dex::u4 base_offset,
566                                         dex::u4 payload_offset) {
567   auto instr = sparse_switches_[payload_offset];
568   SLICER_CHECK(instr != nullptr);
569 
570   auto payload = bytecode_.ptr<dex::SparseSwitchPayload>(payload_offset * 2);
571   SLICER_CHECK(payload->ident == dex::kSparseSwitchSignature);
572 
573   dex::s4* const targets = payload->data + payload->size;
574   SLICER_CHECK(reinterpret_cast<dex::u1*>(targets + payload->size) <=
575         bytecode_.data() + bytecode_.size());
576 
577   for (int i = 0; i < payload->size; ++i) {
578     auto label = instr->switch_cases[i].target;
579     assert(label->offset != kInvalidOffset);
580     targets[i] = label->offset - base_offset;
581   }
582 }
583 
FixupLabels()584 void BytecodeEncoder::FixupLabels() {
585   for (const LabelFixup& fixup : fixups_) {
586     dex::u4 label_offset = fixup.label->offset;
587     assert(label_offset != kInvalidOffset);
588     assert(label_offset > fixup.offset);
589     dex::u4 rel_offset = label_offset - fixup.offset;
590     SLICER_CHECK(rel_offset != 0);
591     dex::u2* instr = bytecode_.ptr<dex::u2>(fixup.offset * 2);
592     if (fixup.short_fixup) {
593       // TODO: explicit out-of-range check
594       assert(instr[1] == 0);
595       instr[1] = Pack_16(rel_offset);
596     } else {
597       assert(instr[1] == 0);
598       assert(instr[2] == 0);
599       instr[1] = Pack_16(rel_offset & 0xffff);
600       instr[2] = Pack_16(rel_offset >> 16);
601     }
602   }
603 }
604 
Encode(ir::Code * ir_code,std::shared_ptr<ir::DexFile> dex_ir)605 void BytecodeEncoder::Encode(ir::Code* ir_code, std::shared_ptr<ir::DexFile> dex_ir) {
606   SLICER_CHECK(bytecode_.empty());
607   SLICER_CHECK(offset_ == 0);
608   SLICER_CHECK(outs_count_ == 0);
609 
610   packed_switches_.clear();
611   sparse_switches_.clear();
612 
613   // reset all instruction offsets
614   for (auto instr : instructions_) {
615     instr->offset = kInvalidOffset;
616   }
617 
618   // generate the .dex bytecodes
619   for (auto instr : instructions_) {
620     instr->Accept(this);
621   }
622 
623   // no more appending (read & write is ok)
624   bytecode_.Seal(2);
625 
626   FixupLabels();
627   FixupSwitchOffsets();
628 
629   // update ir::Code
630   ir_code->instructions = slicer::ArrayView<const dex::u2>(
631       bytecode_.ptr<dex::u2>(0), bytecode_.size() / 2);
632   ir_code->outs_count = outs_count_;
633 
634   // attach the new bytecode
635   dex_ir->AttachBuffer(std::move(bytecode_));
636 }
637 
638 }  // namespace lir
639