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