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