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