• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, Google LLC
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google LLC nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 package com.android.tools.smali.dexlib2.writer;
32 
33 import com.android.tools.smali.dexlib2.iface.instruction.formats.ArrayPayload;
34 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction10t;
35 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction10x;
36 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11n;
37 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x;
38 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction12x;
39 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction20bc;
40 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction20t;
41 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c;
42 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21ih;
43 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21lh;
44 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21s;
45 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21t;
46 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22b;
47 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c;
48 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22cs;
49 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22s;
50 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22t;
51 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22x;
52 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction23x;
53 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction30t;
54 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31c;
55 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i;
56 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31t;
57 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction32x;
58 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c;
59 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35mi;
60 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35ms;
61 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc;
62 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rmi;
63 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rms;
64 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction45cc;
65 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction4rcc;
66 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction51l;
67 import com.android.tools.smali.dexlib2.iface.instruction.formats.PackedSwitchPayload;
68 import com.android.tools.smali.dexlib2.iface.instruction.formats.SparseSwitchPayload;
69 import com.android.tools.smali.dexlib2.iface.reference.CallSiteReference;
70 import com.android.tools.smali.dexlib2.iface.reference.FieldReference;
71 import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference;
72 import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference;
73 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
74 import com.android.tools.smali.dexlib2.iface.reference.Reference;
75 import com.android.tools.smali.dexlib2.iface.reference.StringReference;
76 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
77 import com.android.tools.smali.dexlib2.Opcode;
78 import com.android.tools.smali.dexlib2.Opcodes;
79 import com.android.tools.smali.dexlib2.ReferenceType;
80 import com.android.tools.smali.dexlib2.iface.instruction.DualReferenceInstruction;
81 import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction;
82 import com.android.tools.smali.dexlib2.iface.instruction.SwitchElement;
83 import com.android.tools.smali.util.CollectionUtils;
84 import com.android.tools.smali.util.ExceptionWithContext;
85 
86 import javax.annotation.Nonnull;
87 import java.io.IOException;
88 import java.util.ArrayList;
89 import java.util.Collections;
90 import java.util.Comparator;
91 import java.util.List;
92 
93 public class InstructionWriter<StringRef extends StringReference, TypeRef extends TypeReference,
94         FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
95         ProtoRefKey extends MethodProtoReference, MethodHandleKey extends MethodHandleReference,
96         CallSiteKey extends CallSiteReference> {
97     @Nonnull private final Opcodes opcodes;
98     @Nonnull private final DexDataWriter writer;
99     @Nonnull private final StringSection<?, StringRef> stringSection;
100     @Nonnull private final TypeSection<?, ?, TypeRef> typeSection;
101     @Nonnull private final FieldSection<?, ?, FieldRefKey, ?> fieldSection;
102     @Nonnull private final MethodSection<?, ?, ?, MethodRefKey, ?> methodSection;
103     @Nonnull private final ProtoSection<?, ?, ProtoRefKey, ?> protoSection;
104     @Nonnull private final MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection;
105     @Nonnull private final CallSiteSection<CallSiteKey, ?> callSiteSection;
106 
107     @Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference,
108             FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
109             ProtoRefKey extends MethodProtoReference, MethodHandleKey extends MethodHandleReference,
110             CallSiteKey extends CallSiteReference>
111             InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey, MethodHandleKey, CallSiteKey>
makeInstructionWriter( @onnull Opcodes opcodes, @Nonnull DexDataWriter writer, @Nonnull StringSection<?, StringRef> stringSection, @Nonnull TypeSection<?, ?, TypeRef> typeSection, @Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection, @Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection, @Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection, @Nonnull MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection, @Nonnull CallSiteSection<CallSiteKey, ?> callSiteSection)112             makeInstructionWriter(
113                 @Nonnull Opcodes opcodes,
114                 @Nonnull DexDataWriter writer,
115                 @Nonnull StringSection<?, StringRef> stringSection,
116                 @Nonnull TypeSection<?, ?, TypeRef> typeSection,
117                 @Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
118                 @Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
119                 @Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection,
120                 @Nonnull MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection,
121                 @Nonnull CallSiteSection<CallSiteKey, ?> callSiteSection) {
122         return new InstructionWriter<
123                 StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey, MethodHandleKey,CallSiteKey>(
124                         opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection,
125                         methodHandleSection, callSiteSection);
126     }
127 
InstructionWriter(@onnull Opcodes opcodes, @Nonnull DexDataWriter writer, @Nonnull StringSection<?, StringRef> stringSection, @Nonnull TypeSection<?, ?, TypeRef> typeSection, @Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection, @Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection, @Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection, @Nonnull MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection, @Nonnull CallSiteSection<CallSiteKey, ?> callSiteSection)128     InstructionWriter(@Nonnull Opcodes opcodes,
129                       @Nonnull DexDataWriter writer,
130                       @Nonnull StringSection<?, StringRef> stringSection,
131                       @Nonnull TypeSection<?, ?, TypeRef> typeSection,
132                       @Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
133                       @Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
134                       @Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection,
135                       @Nonnull MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection,
136                       @Nonnull CallSiteSection<CallSiteKey, ?> callSiteSection) {
137         this.opcodes = opcodes;
138         this.writer = writer;
139         this.stringSection = stringSection;
140         this.typeSection = typeSection;
141         this.fieldSection = fieldSection;
142         this.methodSection = methodSection;
143         this.protoSection = protoSection;
144         this.methodHandleSection = methodHandleSection;
145         this.callSiteSection = callSiteSection;
146     }
147 
getOpcodeValue(Opcode opcode)148     private short getOpcodeValue(Opcode opcode) {
149         Short value = opcodes.getOpcodeValue(opcode);
150         if (value == null) {
151             throw new ExceptionWithContext("Instruction %s is invalid for api %d", opcode.name, opcodes.api);
152         }
153         return value;
154     }
155 
write(@onnull Instruction10t instruction)156     public void write(@Nonnull Instruction10t instruction) {
157         try {
158             writer.write(getOpcodeValue(instruction.getOpcode()));
159             writer.write(instruction.getCodeOffset());
160         } catch (IOException ex) {
161             throw new RuntimeException(ex);
162         }
163     }
164 
write(@onnull Instruction10x instruction)165     public void write(@Nonnull Instruction10x instruction) {
166         try {
167             writer.write(getOpcodeValue(instruction.getOpcode()));
168             writer.write(0);
169         } catch (IOException ex) {
170             throw new RuntimeException(ex);
171         }
172     }
173 
write(@onnull Instruction11n instruction)174     public void write(@Nonnull Instruction11n instruction) {
175         try {
176             writer.write(getOpcodeValue(instruction.getOpcode()));
177             writer.write(packNibbles(instruction.getRegisterA(), instruction.getNarrowLiteral()));
178         } catch (IOException ex) {
179             throw new RuntimeException(ex);
180         }
181     }
182 
write(@onnull Instruction11x instruction)183     public void write(@Nonnull Instruction11x instruction) {
184         try {
185             writer.write(getOpcodeValue(instruction.getOpcode()));
186             writer.write(instruction.getRegisterA());
187         } catch (IOException ex) {
188             throw new RuntimeException(ex);
189         }
190     }
191 
write(@onnull Instruction12x instruction)192     public void write(@Nonnull Instruction12x instruction) {
193         try {
194             writer.write(getOpcodeValue(instruction.getOpcode()));
195             writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
196         } catch (IOException ex) {
197             throw new RuntimeException(ex);
198         }
199     }
200 
write(@onnull Instruction20bc instruction)201     public void write(@Nonnull Instruction20bc instruction) {
202         try {
203             writer.write(getOpcodeValue(instruction.getOpcode()));
204             writer.write(instruction.getVerificationError());
205             writer.writeUshort(getReferenceIndex(instruction));
206         } catch (IOException ex) {
207             throw new RuntimeException(ex);
208         }
209     }
210 
write(@onnull Instruction20t instruction)211     public void write(@Nonnull Instruction20t instruction) {
212         try {
213             writer.write(getOpcodeValue(instruction.getOpcode()));
214             writer.write(0);
215             writer.writeShort(instruction.getCodeOffset());
216         } catch (IOException ex) {
217             throw new RuntimeException(ex);
218         }
219     }
220 
write(@onnull Instruction21c instruction)221     public void write(@Nonnull Instruction21c instruction) {
222         try {
223             writer.write(getOpcodeValue(instruction.getOpcode()));
224             writer.write(instruction.getRegisterA());
225             writer.writeUshort(getReferenceIndex(instruction));
226         } catch (IOException ex) {
227             throw new RuntimeException(ex);
228         }
229     }
230 
write(@onnull Instruction21ih instruction)231     public void write(@Nonnull Instruction21ih instruction) {
232         try {
233             writer.write(getOpcodeValue(instruction.getOpcode()));
234             writer.write(instruction.getRegisterA());
235             writer.writeShort(instruction.getHatLiteral());
236         } catch (IOException ex) {
237             throw new RuntimeException(ex);
238         }
239     }
240 
write(@onnull Instruction21lh instruction)241     public void write(@Nonnull Instruction21lh instruction) {
242         try {
243             writer.write(getOpcodeValue(instruction.getOpcode()));
244             writer.write(instruction.getRegisterA());
245             writer.writeShort(instruction.getHatLiteral());
246         } catch (IOException ex) {
247             throw new RuntimeException(ex);
248         }
249     }
250 
write(@onnull Instruction21s instruction)251     public void write(@Nonnull Instruction21s instruction) {
252         try {
253             writer.write(getOpcodeValue(instruction.getOpcode()));
254             writer.write(instruction.getRegisterA());
255             writer.writeShort(instruction.getNarrowLiteral());
256         } catch (IOException ex) {
257             throw new RuntimeException(ex);
258         }
259     }
260 
write(@onnull Instruction21t instruction)261     public void write(@Nonnull Instruction21t instruction) {
262         try {
263             writer.write(getOpcodeValue(instruction.getOpcode()));
264             writer.write(instruction.getRegisterA());
265             writer.writeShort(instruction.getCodeOffset());
266         } catch (IOException ex) {
267             throw new RuntimeException(ex);
268         }
269     }
270 
write(@onnull Instruction22b instruction)271     public void write(@Nonnull Instruction22b instruction) {
272         try {
273             writer.write(getOpcodeValue(instruction.getOpcode()));
274             writer.write(instruction.getRegisterA());
275             writer.write(instruction.getRegisterB());
276             writer.write(instruction.getNarrowLiteral());
277         } catch (IOException ex) {
278             throw new RuntimeException(ex);
279         }
280     }
281 
write(@onnull Instruction22c instruction)282     public void write(@Nonnull Instruction22c instruction) {
283         try {
284             writer.write(getOpcodeValue(instruction.getOpcode()));
285             writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
286             writer.writeUshort(getReferenceIndex(instruction));
287         } catch (IOException ex) {
288             throw new RuntimeException(ex);
289         }
290     }
291 
write(@onnull Instruction22cs instruction)292     public void write(@Nonnull Instruction22cs instruction) {
293         try {
294             writer.write(getOpcodeValue(instruction.getOpcode()));
295             writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
296             writer.writeUshort(instruction.getFieldOffset());
297         } catch (IOException ex) {
298             throw new RuntimeException(ex);
299         }
300     }
301 
write(@onnull Instruction22s instruction)302     public void write(@Nonnull Instruction22s instruction) {
303         try {
304             writer.write(getOpcodeValue(instruction.getOpcode()));
305             writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
306             writer.writeShort(instruction.getNarrowLiteral());
307         } catch (IOException ex) {
308             throw new RuntimeException(ex);
309         }
310     }
311 
write(@onnull Instruction22t instruction)312     public void write(@Nonnull Instruction22t instruction) {
313         try {
314             writer.write(getOpcodeValue(instruction.getOpcode()));
315             writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
316             writer.writeShort(instruction.getCodeOffset());
317         } catch (IOException ex) {
318             throw new RuntimeException(ex);
319         }
320     }
321 
write(@onnull Instruction22x instruction)322     public void write(@Nonnull Instruction22x instruction) {
323         try {
324             writer.write(getOpcodeValue(instruction.getOpcode()));
325             writer.write(instruction.getRegisterA());
326             writer.writeUshort(instruction.getRegisterB());
327         } catch (IOException ex) {
328             throw new RuntimeException(ex);
329         }
330     }
331 
write(@onnull Instruction23x instruction)332     public void write(@Nonnull Instruction23x instruction) {
333         try {
334             writer.write(getOpcodeValue(instruction.getOpcode()));
335             writer.write(instruction.getRegisterA());
336             writer.write(instruction.getRegisterB());
337             writer.write(instruction.getRegisterC());
338         } catch (IOException ex) {
339             throw new RuntimeException(ex);
340         }
341     }
342 
write(@onnull Instruction30t instruction)343     public void write(@Nonnull Instruction30t instruction) {
344         try {
345             writer.write(getOpcodeValue(instruction.getOpcode()));
346             writer.write(0);
347             writer.writeInt(instruction.getCodeOffset());
348         } catch (IOException ex) {
349             throw new RuntimeException(ex);
350         }
351     }
352 
write(@onnull Instruction31c instruction)353     public void write(@Nonnull Instruction31c instruction) {
354         try {
355             writer.write(getOpcodeValue(instruction.getOpcode()));
356             writer.write(instruction.getRegisterA());
357             writer.writeInt(getReferenceIndex(instruction));
358         } catch (IOException ex) {
359             throw new RuntimeException(ex);
360         }
361     }
362 
write(@onnull Instruction31i instruction)363     public void write(@Nonnull Instruction31i instruction) {
364         try {
365             writer.write(getOpcodeValue(instruction.getOpcode()));
366             writer.write(instruction.getRegisterA());
367             writer.writeInt(instruction.getNarrowLiteral());
368         } catch (IOException ex) {
369             throw new RuntimeException(ex);
370         }
371     }
372 
write(@onnull Instruction31t instruction)373     public void write(@Nonnull Instruction31t instruction) {
374         try {
375             writer.write(getOpcodeValue(instruction.getOpcode()));
376             writer.write(instruction.getRegisterA());
377             writer.writeInt(instruction.getCodeOffset());
378         } catch (IOException ex) {
379             throw new RuntimeException(ex);
380         }
381     }
382 
write(@onnull Instruction32x instruction)383     public void write(@Nonnull Instruction32x instruction) {
384         try {
385             writer.write(getOpcodeValue(instruction.getOpcode()));
386             writer.write(0);
387             writer.writeUshort(instruction.getRegisterA());
388             writer.writeUshort(instruction.getRegisterB());
389         } catch (IOException ex) {
390             throw new RuntimeException(ex);
391         }
392     }
393 
write(@onnull Instruction35c instruction)394     public void write(@Nonnull Instruction35c instruction) {
395         try {
396             writer.write(getOpcodeValue(instruction.getOpcode()));
397             writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
398             writer.writeUshort(getReferenceIndex(instruction));
399             writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
400             writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
401         } catch (IOException ex) {
402             throw new RuntimeException(ex);
403         }
404     }
405 
write(@onnull Instruction35mi instruction)406     public void write(@Nonnull Instruction35mi instruction) {
407         try {
408             writer.write(getOpcodeValue(instruction.getOpcode()));
409             writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
410             writer.writeUshort(instruction.getInlineIndex());
411             writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
412             writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
413         } catch (IOException ex) {
414             throw new RuntimeException(ex);
415         }
416     }
417 
write(@onnull Instruction35ms instruction)418     public void write(@Nonnull Instruction35ms instruction) {
419         try {
420             writer.write(getOpcodeValue(instruction.getOpcode()));
421             writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
422             writer.writeUshort(instruction.getVtableIndex());
423             writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
424             writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
425         } catch (IOException ex) {
426             throw new RuntimeException(ex);
427         }
428     }
429 
write(@onnull Instruction3rc instruction)430     public void write(@Nonnull Instruction3rc instruction) {
431         try {
432             writer.write(getOpcodeValue(instruction.getOpcode()));
433             writer.write(instruction.getRegisterCount());
434             writer.writeUshort(getReferenceIndex(instruction));
435             writer.writeUshort(instruction.getStartRegister());
436         } catch (IOException ex) {
437             throw new RuntimeException(ex);
438         }
439     }
440 
write(@onnull Instruction3rmi instruction)441     public void write(@Nonnull Instruction3rmi instruction) {
442         try {
443             writer.write(getOpcodeValue(instruction.getOpcode()));
444             writer.write(instruction.getRegisterCount());
445             writer.writeUshort(instruction.getInlineIndex());
446             writer.writeUshort(instruction.getStartRegister());
447         } catch (IOException ex) {
448             throw new RuntimeException(ex);
449         }
450     }
451 
452 
write(@onnull Instruction3rms instruction)453     public void write(@Nonnull Instruction3rms instruction) {
454         try {
455             writer.write(getOpcodeValue(instruction.getOpcode()));
456             writer.write(instruction.getRegisterCount());
457             writer.writeUshort(instruction.getVtableIndex());
458             writer.writeUshort(instruction.getStartRegister());
459         } catch (IOException ex) {
460             throw new RuntimeException(ex);
461         }
462     }
463 
write(@onnull Instruction45cc instruction)464     public void write(@Nonnull Instruction45cc instruction) {
465         try {
466             writer.write(getOpcodeValue(instruction.getOpcode()));
467             writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
468             writer.writeUshort(getReferenceIndex(instruction));
469             writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
470             writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
471             writer.writeUshort(getReference2Index(instruction));
472         } catch (IOException ex) {
473             throw new RuntimeException(ex);
474         }
475     }
476 
write(@onnull Instruction4rcc instruction)477     public void write(@Nonnull Instruction4rcc instruction) {
478         try {
479             writer.write(getOpcodeValue(instruction.getOpcode()));
480             writer.write(instruction.getRegisterCount());
481             writer.writeUshort(getReferenceIndex(instruction));
482             writer.writeUshort(instruction.getStartRegister());
483             writer.writeUshort(getReference2Index(instruction));
484         } catch (IOException ex) {
485             throw new RuntimeException(ex);
486         }
487     }
488 
write(@onnull Instruction51l instruction)489     public void write(@Nonnull Instruction51l instruction) {
490         try {
491             writer.write(getOpcodeValue(instruction.getOpcode()));
492             writer.write(instruction.getRegisterA());
493             writer.writeLong(instruction.getWideLiteral());
494         } catch (IOException ex) {
495             throw new RuntimeException(ex);
496         }
497     }
498 
write(@onnull ArrayPayload instruction)499     public void write(@Nonnull ArrayPayload instruction) {
500         try {
501             writer.writeUshort(getOpcodeValue(instruction.getOpcode()));
502             writer.writeUshort(instruction.getElementWidth());
503             List<Number> elements = instruction.getArrayElements();
504             writer.writeInt(elements.size());
505             switch (instruction.getElementWidth()) {
506                 case 1:
507                     for (Number element: elements) {
508                         writer.write(element.byteValue());
509                     }
510                     break;
511                 case 2:
512                     for (Number element: elements) {
513                         writer.writeShort(element.shortValue());
514                     }
515                     break;
516                 case 4:
517                     for (Number element: elements) {
518                         writer.writeInt(element.intValue());
519                     }
520                     break;
521                 case 8:
522                     for (Number element: elements) {
523                         writer.writeLong(element.longValue());
524                     }
525                     break;
526             }
527             if ((writer.getPosition() & 1) != 0) {
528                 writer.write(0);
529             }
530         } catch (IOException ex) {
531             throw new RuntimeException(ex);
532         }
533     }
534 
write(@onnull SparseSwitchPayload instruction)535     public void write(@Nonnull SparseSwitchPayload instruction) {
536         try {
537             writer.writeUbyte(0);
538             writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
539             List<? extends SwitchElement> elements = CollectionUtils.immutableSortedCopy(
540                     instruction.getSwitchElements(), switchElementComparator);
541 
542             writer.writeUshort(elements.size());
543             for (SwitchElement element: elements) {
544                 writer.writeInt(element.getKey());
545             }
546             for (SwitchElement element: elements) {
547                 writer.writeInt(element.getOffset());
548             }
549         } catch (IOException ex) {
550             throw new RuntimeException(ex);
551         }
552     }
553 
554     private final Comparator<SwitchElement> switchElementComparator = new Comparator<SwitchElement>() {
555         @Override public int compare(SwitchElement element1, SwitchElement element2) {
556             return Integer.compare(element1.getKey(), element2.getKey());
557         }
558     };
559 
write(@onnull PackedSwitchPayload instruction)560     public void write(@Nonnull PackedSwitchPayload instruction) {
561         try {
562             writer.writeUbyte(0);
563             writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
564             List<? extends SwitchElement> elements = instruction.getSwitchElements();
565             writer.writeUshort(elements.size());
566             if (elements.size() == 0) {
567                 writer.writeInt(0);
568             } else {
569                 writer.writeInt(elements.get(0).getKey());
570                 for (SwitchElement element: elements) {
571                     writer.writeInt(element.getOffset());
572                 }
573             }
574         } catch (IOException ex) {
575             throw new RuntimeException(ex);
576         }
577     }
578 
packNibbles(int a, int b)579     private static int packNibbles(int a, int b) {
580         return (b << 4) | a;
581     }
582 
getReferenceIndex(ReferenceInstruction referenceInstruction)583     private int getReferenceIndex(ReferenceInstruction referenceInstruction) {
584         return getReferenceIndex(referenceInstruction.getReferenceType(),
585                 referenceInstruction.getReference());
586     }
587 
getReference2Index(DualReferenceInstruction referenceInstruction)588     private int getReference2Index(DualReferenceInstruction referenceInstruction) {
589         return getReferenceIndex(referenceInstruction.getReferenceType2(),
590                 referenceInstruction.getReference2());
591     }
592 
getReferenceIndex(int referenceType, Reference reference)593     private int getReferenceIndex(int referenceType, Reference reference) {
594         switch (referenceType) {
595             case ReferenceType.FIELD:
596                 return fieldSection.getItemIndex((FieldRefKey) reference);
597             case ReferenceType.METHOD:
598                 return methodSection.getItemIndex((MethodRefKey) reference);
599             case ReferenceType.STRING:
600                 return stringSection.getItemIndex((StringRef) reference);
601             case ReferenceType.TYPE:
602                 return typeSection.getItemIndex((TypeRef) reference);
603             case ReferenceType.METHOD_PROTO:
604                 return protoSection.getItemIndex((ProtoRefKey) reference);
605             case ReferenceType.METHOD_HANDLE:
606                 return methodHandleSection.getItemIndex((MethodHandleKey) reference);
607             case ReferenceType.CALL_SITE:
608                 return callSiteSection.getItemIndex((CallSiteKey) reference);
609             default:
610                 throw new ExceptionWithContext("Unknown reference type: %d",  referenceType);
611         }
612     }
613 }
614