1 /* 2 * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 package jdk.internal.classfile.impl; 27 28 import java.lang.classfile.*; 29 import java.lang.classfile.attribute.CodeAttribute; 30 import java.lang.classfile.attribute.LineNumberTableAttribute; 31 import java.lang.classfile.constantpool.*; 32 import java.lang.classfile.instruction.CharacterRange; 33 import java.lang.classfile.instruction.ExceptionCatch; 34 import java.lang.classfile.instruction.LocalVariable; 35 import java.lang.classfile.instruction.LocalVariableType; 36 import java.lang.classfile.instruction.SwitchCase; 37 import java.lang.constant.ClassDesc; 38 import java.lang.constant.MethodTypeDesc; 39 import java.util.*; 40 import java.util.function.Consumer; 41 import java.util.function.Function; 42 43 import static java.lang.constant.ConstantDescs.INIT_NAME; 44 import static java.util.Objects.requireNonNull; 45 import static jdk.internal.classfile.impl.BytecodeHelpers.*; 46 import static jdk.internal.classfile.impl.RawBytecodeHelper.*; 47 48 public final class DirectCodeBuilder 49 extends AbstractDirectBuilder<CodeModel> 50 implements TerminalCodeBuilder { 51 private static final CharacterRange[] EMPTY_CHARACTER_RANGE = {}; 52 private static final DeferredLabel[] EMPTY_LABEL_ARRAY = {}; 53 private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {}; 54 private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {}; 55 private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {}; 56 private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {}; 57 58 final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers = new ArrayList<>(); 59 private CharacterRange[] characterRanges = EMPTY_CHARACTER_RANGE; 60 private LocalVariable[] localVariables = EMPTY_LOCAL_VARIABLE_ARRAY; 61 private LocalVariableType[] localVariableTypes = EMPTY_LOCAL_VARIABLE_TYPE_ARRAY; 62 private int characterRangesCount = 0; 63 private int localVariablesCount = 0; 64 private int localVariableTypesCount = 0; 65 private final boolean transformDeferredJumps, transformKnownJumps; 66 private final Label startLabel, endLabel; 67 final MethodInfo methodInfo; 68 final BufWriterImpl bytecodesBufWriter; 69 private CodeAttribute mruParent; 70 private int[] mruParentTable; 71 private Map<CodeAttribute, int[]> parentMap; 72 private DedupLineNumberTableAttribute lineNumberWriter; 73 private int topLocal; 74 75 private DeferredLabel[] deferredLabels = EMPTY_DEFERRED_LABEL_ARRAY; 76 private int deferredLabelsCount = 0; 77 78 /* Locals management 79 lazily computed maxLocal = -1 80 first time: derive count from methodType descriptor (for new methods) & ACC_STATIC, 81 or model maxLocals (for transformation) 82 block builders inherit parent count 83 allocLocal(TypeKind) bumps by nSlots 84 */ 85 86 public static UnboundAttribute<CodeAttribute> build(MethodInfo methodInfo, 87 Consumer<? super CodeBuilder> handler, 88 SplitConstantPool constantPool, 89 ClassFileImpl context, 90 CodeModel original) { 91 DirectCodeBuilder cb; 92 try { 93 handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, false)); 94 cb.buildContent(); 95 } catch (LabelOverflowException loe) { 96 if (context.fixShortJumps()) { 97 handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, true)); 98 cb.buildContent(); 99 } 100 else 101 throw loe; 102 } 103 return cb.content; 104 } 105 106 private DirectCodeBuilder(MethodInfo methodInfo, 107 SplitConstantPool constantPool, 108 ClassFileImpl context, 109 CodeModel original, 110 boolean transformDeferredJumps) { 111 super(constantPool, context); 112 setOriginal(original); 113 this.methodInfo = methodInfo; 114 this.transformDeferredJumps = transformDeferredJumps; 115 this.transformKnownJumps = context.fixShortJumps(); 116 bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength()) 117 : new BufWriterImpl(constantPool, context); 118 this.startLabel = new LabelImpl(this, 0); 119 this.endLabel = new LabelImpl(this, -1); 120 this.topLocal = TerminalCodeBuilder.setupTopLocal(methodInfo, original); 121 } 122 123 @Override 124 public CodeBuilder with(CodeElement element) { 125 if (element instanceof AbstractElement ae) { 126 ae.writeTo(this); 127 } else { 128 writeAttribute((CustomAttribute<?>) requireNonNull(element)); 129 } 130 return this; 131 } 132 133 @Override 134 public Label newLabel() { 135 return new LabelImpl(this, -1); 136 } 137 138 @Override 139 public Label startLabel() { 140 return startLabel; 141 } 142 143 @Override 144 public Label endLabel() { 145 return endLabel; 146 } 147 148 @Override 149 public int receiverSlot() { 150 return methodInfo.receiverSlot(); 151 } 152 153 @Override 154 public int parameterSlot(int paramNo) { 155 return methodInfo.parameterSlot(paramNo); 156 } 157 158 public int curTopLocal() { 159 return topLocal; 160 } 161 162 @Override 163 public int allocateLocal(TypeKind typeKind) { 164 int retVal = topLocal; 165 topLocal += typeKind.slotSize(); 166 return retVal; 167 } 168 169 public int curPc() { 170 return bytecodesBufWriter.size(); 171 } 172 173 public MethodInfo methodInfo() { 174 return methodInfo; 175 } 176 177 private UnboundAttribute<CodeAttribute> content = null; 178 179 private void writeExceptionHandlers(BufWriterImpl buf) { 180 int pos = buf.size(); 181 int handlersSize = handlers.size(); 182 buf.writeU2(handlersSize); 183 if (handlersSize > 0) { 184 writeExceptionHandlers(buf, pos); 185 } 186 } 187 188 private void writeExceptionHandlers(BufWriterImpl buf, int pos) { 189 int handlersSize = handlers.size(); 190 for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) { 191 int startPc = labelToBci(h.tryStart()); 192 int endPc = labelToBci(h.tryEnd()); 193 int handlerPc = labelToBci(h.handler()); 194 if (startPc == -1 || endPc == -1 || handlerPc == -1) { 195 if (context.dropDeadLabels()) { 196 handlersSize--; 197 } else { 198 throw new IllegalArgumentException("Unbound label in exception handler"); 199 } 200 } else { 201 buf.writeU2U2U2(startPc, endPc, handlerPc); 202 buf.writeIndexOrZero(h.catchTypeEntry()); 203 handlersSize++; 204 } 205 } 206 if (handlersSize < handlers.size()) 207 buf.patchU2(pos, handlersSize); 208 } 209 210 private void buildContent() { 211 if (content != null) return; 212 setLabelTarget(endLabel); 213 214 // Backfill branches for which Label didn't have position yet 215 processDeferredLabels(); 216 217 if (context.passDebugElements()) { 218 if (characterRangesCount > 0) { 219 Attribute<?> a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { 220 221 @Override 222 public void writeBody(BufWriterImpl b) { 223 int pos = b.size(); 224 int crSize = characterRangesCount; 225 b.writeU2(crSize); 226 for (int i = 0; i < characterRangesCount; i++) { 227 CharacterRange cr = characterRanges[i]; 228 var start = labelToBci(cr.startScope()); 229 var end = labelToBci(cr.endScope()); 230 if (start == -1 || end == -1) { 231 if (context.dropDeadLabels()) { 232 crSize--; 233 } else { 234 throw new IllegalArgumentException("Unbound label in character range"); 235 } 236 } else { 237 b.writeU2U2(start, end - 1); 238 b.writeIntInt(cr.characterRangeStart(), cr.characterRangeEnd()); 239 b.writeU2(cr.flags()); 240 } 241 } 242 if (crSize < characterRangesCount) 243 b.patchU2(pos, crSize); 244 } 245 246 @Override 247 public Utf8Entry attributeName() { 248 return constantPool.utf8Entry(Attributes.NAME_CHARACTER_RANGE_TABLE); 249 } 250 }; 251 attributes.withAttribute(a); 252 } 253 254 if (localVariablesCount > 0) { 255 Attribute<?> a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { 256 @Override 257 public void writeBody(BufWriterImpl b) { 258 int pos = b.size(); 259 int lvSize = localVariablesCount; 260 b.writeU2(lvSize); 261 for (int i = 0; i < localVariablesCount; i++) { 262 LocalVariable l = localVariables[i]; 263 if (!Util.writeLocalVariable(b, l)) { 264 if (context.dropDeadLabels()) { 265 lvSize--; 266 } else { 267 throw new IllegalArgumentException("Unbound label in local variable type"); 268 } 269 } 270 } 271 if (lvSize < localVariablesCount) 272 b.patchU2(pos, lvSize); 273 } 274 275 @Override 276 public Utf8Entry attributeName() { 277 return constantPool.utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TABLE); 278 } 279 }; 280 attributes.withAttribute(a); 281 } 282 283 if (localVariableTypesCount > 0) { 284 Attribute<?> a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { 285 @Override 286 public void writeBody(BufWriterImpl b) { 287 int pos = b.size(); 288 int lvtSize = localVariableTypesCount; 289 b.writeU2(lvtSize); 290 for (int i = 0; i < localVariableTypesCount; i++) { 291 LocalVariableType l = localVariableTypes[i]; 292 if (!Util.writeLocalVariable(b, l)) { 293 if (context.dropDeadLabels()) { 294 lvtSize--; 295 } else { 296 throw new IllegalArgumentException("Unbound label in local variable type"); 297 } 298 } 299 } 300 if (lvtSize < localVariableTypesCount) 301 b.patchU2(pos, lvtSize); 302 } 303 304 @Override 305 public Utf8Entry attributeName() { 306 return constantPool.utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TYPE_TABLE); 307 } 308 }; 309 attributes.withAttribute(a); 310 } 311 } 312 313 if (lineNumberWriter != null) { 314 attributes.withAttribute(lineNumberWriter); 315 } 316 317 content = new UnboundAttribute.AdHocAttribute<>(Attributes.code()) { 318 319 private void writeCounters(boolean codeMatch, BufWriterImpl buf) { 320 if (codeMatch) { 321 var originalAttribute = (CodeImpl) original; 322 buf.writeU2U2(originalAttribute.maxStack(), originalAttribute.maxLocals()); 323 } else { 324 StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf); 325 buf.writeU2U2(cntr.maxStack(), cntr.maxLocals()); 326 } 327 } 328 329 private void generateStackMaps(BufWriterImpl buf) throws IllegalArgumentException { 330 //new instance of generator immediately calculates maxStack, maxLocals, all frames, 331 // patches dead bytecode blocks and removes them from exception table 332 var dcb = DirectCodeBuilder.this; 333 StackMapGenerator gen = StackMapGenerator.of(dcb, buf); 334 dcb.attributes.withAttribute(gen.stackMapTableAttribute()); 335 buf.writeU2U2(gen.maxStack(), gen.maxLocals()); 336 } 337 338 private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) { 339 if (buf.getMajorVersion() >= ClassFile.JAVA_6_VERSION) { 340 try { 341 generateStackMaps(buf); 342 } catch (IllegalArgumentException e) { 343 //failover following JVMS-4.10 344 if (buf.getMajorVersion() == ClassFile.JAVA_6_VERSION) { 345 writeCounters(codeMatch, buf); 346 } else { 347 throw e; 348 } 349 } 350 } else { 351 writeCounters(codeMatch, buf); 352 } 353 } 354 355 @Override 356 public void writeBody(BufWriterImpl buf) { 357 DirectCodeBuilder dcb = DirectCodeBuilder.this; 358 buf.setLabelContext(dcb); 359 360 int codeLength = curPc(); 361 if (codeLength == 0 || codeLength >= 65536) { 362 throw new IllegalArgumentException(String.format( 363 "Code length %d is outside the allowed range in %s%s", 364 codeLength, 365 dcb.methodInfo.methodName().stringValue(), 366 dcb.methodInfo.methodTypeSymbol().displayDescriptor())); 367 } 368 369 boolean codeMatch = dcb.codeAndExceptionsMatch(codeLength, buf); 370 var context = dcb.context; 371 if (context.stackMapsWhenRequired()) { 372 if (codeMatch) { 373 dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null)); 374 writeCounters(true, buf); 375 } else { 376 tryGenerateStackMaps(false, buf); 377 } 378 } else if (context.generateStackMaps()) { 379 generateStackMaps(buf); 380 } else if (context.dropStackMaps()) { 381 writeCounters(codeMatch, buf); 382 } 383 384 buf.writeInt(codeLength); 385 buf.writeBytes(dcb.bytecodesBufWriter); 386 dcb.writeExceptionHandlers(buf); 387 dcb.attributes.writeTo(buf); 388 buf.setLabelContext(null); 389 } 390 391 @Override 392 public Utf8Entry attributeName() { 393 return constantPool.utf8Entry(Attributes.NAME_CODE); 394 } 395 }; 396 } 397 398 private static class DedupLineNumberTableAttribute extends UnboundAttribute.AdHocAttribute<LineNumberTableAttribute> { 399 private final BufWriterImpl buf; 400 private int lastPc, lastLine, writtenLine; 401 402 public DedupLineNumberTableAttribute(ConstantPoolBuilder constantPool, ClassFileImpl context) { 403 super(Attributes.lineNumberTable()); 404 buf = new BufWriterImpl(constantPool, context); 405 lastPc = -1; 406 writtenLine = -1; 407 } 408 409 private void push() { 410 //subsequent identical line numbers are skipped 411 if (lastPc >= 0 && lastLine != writtenLine) { 412 buf.writeU2U2(lastPc, lastLine); 413 writtenLine = lastLine; 414 } 415 } 416 417 //writes are expected ordered by pc in ascending sequence 418 public void writeLineNumber(int pc, int lineNo) { 419 //for each pc only the latest line number is written 420 if (lastPc != pc && lastLine != lineNo) { 421 push(); 422 lastPc = pc; 423 } 424 lastLine = lineNo; 425 } 426 427 @Override 428 public void writeBody(BufWriterImpl b) { 429 throw new UnsupportedOperationException(); 430 } 431 432 @Override 433 public void writeTo(BufWriterImpl b) { 434 b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE)); 435 push(); 436 b.writeInt(buf.size() + 2); 437 b.writeU2(buf.size() / 4); 438 b.writeBytes(buf); 439 } 440 441 @Override 442 public Utf8Entry attributeName() { 443 return buf.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE); 444 } 445 } 446 447 private boolean codeAndExceptionsMatch(int codeLength, BufWriterImpl buf) { 448 boolean codeAttributesMatch; 449 if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) { 450 codeAttributesMatch = cai.codeLength == curPc() 451 && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength); 452 if (codeAttributesMatch) { 453 var bw = new BufWriterImpl(constantPool, context); 454 writeExceptionHandlers(bw); 455 codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size()); 456 } 457 458 if (codeAttributesMatch) { 459 var thisIsConstructor = methodInfo.methodName().equalsString(INIT_NAME); 460 var originalIsConstructor = cai.enclosingMethod.methodName().equalsString(INIT_NAME); 461 if (thisIsConstructor || originalIsConstructor) { 462 if (thisIsConstructor != originalIsConstructor) { 463 codeAttributesMatch = false; 464 } 465 } 466 467 if (codeAttributesMatch && thisIsConstructor) { 468 if (!buf.strictFieldsMatch(cai.classReader.getContainedClass())) { 469 codeAttributesMatch = false; 470 } 471 } 472 } 473 } 474 else 475 codeAttributesMatch = false; 476 return codeAttributesMatch; 477 } 478 479 // Writing support 480 481 private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { } 482 483 private void processDeferredLabels() { 484 for (int i = 0; i < deferredLabelsCount; i++) { 485 DeferredLabel dl = deferredLabels[i]; 486 int branchOffset = labelToBci(dl.label) - dl.instructionPc; 487 if (dl.size == 2) { 488 if ((short) branchOffset != branchOffset) throw new LabelOverflowException(); 489 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset); 490 } else { 491 assert dl.size == 4; 492 bytecodesBufWriter.patchInt(dl.labelPc, branchOffset); 493 } 494 } 495 } 496 497 // Instruction writing 498 499 public void writeBytecode(Opcode opcode) { 500 assert !opcode.isWide(); 501 bytecodesBufWriter.writeU1(opcode.bytecode()); 502 } 503 504 // Instruction version, refer to opcode, trusted 505 public void writeLocalVar(Opcode opcode, int slot) { 506 if (opcode.isWide()) { 507 bytecodesBufWriter.writeU2U2(opcode.bytecode(), slot); 508 } else { 509 bytecodesBufWriter.writeU1U1(opcode.bytecode(), slot); 510 } 511 } 512 513 // local var access, not a trusted write method, needs slot validation 514 private void localAccess(int bytecode, int slot) { 515 if ((slot & ~0xFF) == 0) { 516 bytecodesBufWriter.writeU1U1(bytecode, slot); 517 } else { 518 BytecodeHelpers.validateSlot(slot); 519 bytecodesBufWriter.writeU1U1U2(WIDE, bytecode, slot); 520 } 521 } 522 523 public void writeIncrement(boolean wide, int slot, int val) { 524 if (wide) { 525 bytecodesBufWriter.writeU2U2U2((WIDE << 8) | IINC, slot, val); 526 } else { 527 bytecodesBufWriter.writeU1U1U1(IINC, slot, val); 528 } 529 } 530 531 public void writeBranch(Opcode op, Label target) { 532 if (op.sizeIfFixed() == 3) { 533 writeShortJump(op.bytecode(), target); 534 } else { 535 writeLongJump(op.bytecode(), target); 536 } 537 } 538 539 private void writeLongLabelOffset(int instructionPc, Label label) { 540 int targetBci = labelToBci(label); 541 542 // algebraic union of jump | (instructionPc, target), distinguished by null == target. 543 int jumpOrInstructionPc; 544 Label nullOrTarget; 545 if (targetBci == -1) { 546 jumpOrInstructionPc = instructionPc; 547 nullOrTarget = label; 548 } else { 549 jumpOrInstructionPc = targetBci - instructionPc; 550 nullOrTarget = null; 551 } 552 553 writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); 554 } 555 556 private void writeShortJump(int bytecode, Label target) { 557 int instructionPc = curPc(); 558 int targetBci = labelToBci(target); 559 560 // algebraic union of jump | (instructionPc, target), distinguished by null == target. 561 int jumpOrInstructionPc; 562 Label nullOrTarget; 563 if (targetBci == -1) { 564 jumpOrInstructionPc = instructionPc; 565 nullOrTarget = target; 566 } else { 567 jumpOrInstructionPc = targetBci - instructionPc; 568 nullOrTarget = null; 569 } 570 571 //transform short-opcode forward jumps if enforced, and backward jumps if enabled and overflowing 572 if (transformDeferredJumps || transformKnownJumps && nullOrTarget == null && jumpOrInstructionPc < Short.MIN_VALUE) { 573 fixShortJump(bytecode, jumpOrInstructionPc, nullOrTarget); 574 } else { 575 bytecodesBufWriter.writeU1(bytecode); 576 writeParsedShortLabel(jumpOrInstructionPc, nullOrTarget); 577 } 578 } 579 580 private void writeLongJump(int bytecode, Label target) { 581 int instructionPc = curPc(); 582 bytecodesBufWriter.writeU1(bytecode); 583 writeLongLabelOffset(instructionPc, target); 584 } 585 586 private void fixShortJump(int bytecode, int jumpOrInstructionPc, Label nullOrTarget) { 587 if (bytecode == GOTO) { 588 bytecodesBufWriter.writeU1(GOTO_W); 589 writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); 590 } else if (bytecode == JSR) { 591 bytecodesBufWriter.writeU1(JSR_W); 592 writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); 593 } else { 594 bytecodesBufWriter.writeU1U2( 595 BytecodeHelpers.reverseBranchOpcode(bytecode), // u1 596 8); // u1 + s2 + u1 + s4 // s2 597 bytecodesBufWriter.writeU1(GOTO_W); // u1 598 if (nullOrTarget == null) { 599 jumpOrInstructionPc -= 3; // jump -= 3; 600 } else { 601 jumpOrInstructionPc += 3; // instructionPc += 3; 602 } 603 writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); // s4 604 } 605 } 606 607 private void writeParsedShortLabel(int jumpOrInstructionPc, Label nullOrTarget) { 608 if (nullOrTarget == null) { 609 if ((short) jumpOrInstructionPc != jumpOrInstructionPc) 610 throw new LabelOverflowException(); 611 bytecodesBufWriter.writeU2(jumpOrInstructionPc); 612 } else { 613 int pc = bytecodesBufWriter.skip(2); 614 addLabel(new DeferredLabel(pc, 2, jumpOrInstructionPc, nullOrTarget)); 615 } 616 } 617 618 private void writeParsedLongLabel(int jumpOrInstructionPc, Label nullOrTarget) { 619 if (nullOrTarget == null) { 620 bytecodesBufWriter.writeInt(jumpOrInstructionPc); 621 } else { 622 int pc = bytecodesBufWriter.skip(4); 623 addLabel(new DeferredLabel(pc, 4, jumpOrInstructionPc, nullOrTarget)); 624 } 625 } 626 627 public void writeLookupSwitch(Label defaultTarget, List<SwitchCase> cases) { 628 int instructionPc = curPc(); 629 bytecodesBufWriter.writeU1(LOOKUPSWITCH); 630 int pad = 4 - (curPc() % 4); 631 if (pad != 4) 632 bytecodesBufWriter.skip(pad); // padding content can be anything 633 writeLongLabelOffset(instructionPc, defaultTarget); 634 bytecodesBufWriter.writeInt(cases.size()); 635 cases = new ArrayList<>(cases); 636 cases.sort(new Comparator<>() { 637 @Override 638 public int compare(SwitchCase c1, SwitchCase c2) { 639 return Integer.compare(c1.caseValue(), c2.caseValue()); 640 } 641 }); 642 for (var c : cases) { 643 bytecodesBufWriter.writeInt(c.caseValue()); 644 var target = c.target(); 645 writeLongLabelOffset(instructionPc, target); 646 } 647 } 648 649 public void writeTableSwitch(int low, int high, Label defaultTarget, List<SwitchCase> cases) { 650 int instructionPc = curPc(); 651 bytecodesBufWriter.writeU1(TABLESWITCH); 652 int pad = 4 - (curPc() % 4); 653 if (pad != 4) 654 bytecodesBufWriter.skip(pad); // padding content can be anything 655 writeLongLabelOffset(instructionPc, defaultTarget); 656 bytecodesBufWriter.writeIntInt(low, high); 657 var caseMap = new HashMap<Integer, Label>(cases.size()); 658 for (var c : cases) { 659 caseMap.put(c.caseValue(), c.target()); 660 } 661 for (long l = low; l<=high; l++) { 662 var target = caseMap.getOrDefault((int)l, defaultTarget); 663 writeLongLabelOffset(instructionPc, target); 664 } 665 } 666 667 public void writeFieldAccess(Opcode opcode, FieldRefEntry ref) { 668 bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); 669 } 670 671 public void writeInvokeNormal(Opcode opcode, MemberRefEntry ref) { 672 bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); 673 } 674 675 public void writeInvokeInterface(Opcode opcode, 676 InterfaceMethodRefEntry ref, 677 int count) { 678 bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); 679 bytecodesBufWriter.writeU1U1(count, 0); 680 } 681 682 public void writeInvokeDynamic(InvokeDynamicEntry ref) { 683 bytecodesBufWriter.writeU1U2U2(INVOKEDYNAMIC, bytecodesBufWriter.cpIndex(ref), 0); 684 } 685 686 public void writeNewObject(ClassEntry type) { 687 bytecodesBufWriter.writeIndex(NEW, type); 688 } 689 690 public void writeNewPrimitiveArray(int newArrayCode) { 691 bytecodesBufWriter.writeU1U1(NEWARRAY, newArrayCode); 692 } 693 694 public void writeNewReferenceArray(ClassEntry type) { 695 bytecodesBufWriter.writeIndex(ANEWARRAY, type); 696 } 697 698 public void writeNewMultidimensionalArray(int dimensions, ClassEntry type) { 699 bytecodesBufWriter.writeIndex(MULTIANEWARRAY, type); 700 bytecodesBufWriter.writeU1(dimensions); 701 } 702 703 public void writeTypeCheck(Opcode opcode, ClassEntry type) { 704 bytecodesBufWriter.writeIndex(opcode.bytecode(), type); 705 } 706 707 public void writeArgumentConstant(Opcode opcode, int value) { 708 if (opcode.sizeIfFixed() == 3) { 709 bytecodesBufWriter.writeU1U2(opcode.bytecode(), value); 710 } else { 711 bytecodesBufWriter.writeU1U1(opcode.bytecode(), value); 712 } 713 } 714 715 // value may not be writable to this constant pool 716 public void writeAdaptLoadConstant(Opcode opcode, LoadableConstantEntry value) { 717 var pe = AbstractPoolEntry.maybeClone(constantPool, value); 718 int index = pe.index(); 719 if (pe != value && opcode != Opcode.LDC2_W) { 720 // rewrite ldc/ldc_w if external entry; ldc2_w never needs rewrites 721 opcode = index <= 0xFF ? Opcode.LDC : Opcode.LDC_W; 722 } 723 724 writeDirectLoadConstant(opcode, pe); 725 } 726 727 // the loadable entry is writable to this constant pool 728 public void writeDirectLoadConstant(Opcode opcode, LoadableConstantEntry pe) { 729 assert !opcode.isWide() && canWriteDirect(pe.constantPool()); 730 int index = pe.index(); 731 if (opcode.sizeIfFixed() == 3) { 732 bytecodesBufWriter.writeU1U2(opcode.bytecode(), index); 733 } else { 734 bytecodesBufWriter.writeU1U1(opcode.bytecode(), index); 735 } 736 } 737 738 @Override 739 public Label getLabel(int bci) { 740 throw new UnsupportedOperationException("Lookup by BCI not supported by CodeBuilder"); 741 } 742 743 @Override 744 public int labelToBci(Label label) { 745 LabelImpl lab = (LabelImpl) label; 746 LabelContext context = lab.labelContext(); 747 if (context == this) { 748 return lab.getBCI(); 749 } 750 return labelToBci(context, lab); 751 } 752 753 private int labelToBci(LabelContext context, LabelImpl lab) { 754 if (context == mruParent) { 755 return mruParentTable[lab.getBCI()] - 1; 756 } 757 else if (context instanceof CodeAttribute parent) { 758 if (parentMap == null) 759 parentMap = new IdentityHashMap<>(); 760 //critical JDK bootstrap path, cannot use lambda here 761 int[] table = parentMap.computeIfAbsent(parent, new Function<CodeAttribute, int[]>() { 762 @Override 763 public int[] apply(CodeAttribute x) { 764 return new int[parent.codeLength() + 1]; 765 } 766 }); 767 768 mruParent = parent; 769 mruParentTable = table; 770 return mruParentTable[lab.getBCI()] - 1; 771 } 772 else if (context instanceof BufferedCodeBuilder) { 773 // Hijack the label 774 return lab.getBCI(); 775 } 776 else { 777 throw new IllegalStateException(String.format("Unexpected label context %s in =%s", context, this)); 778 } 779 } 780 781 public void setLineNumber(int lineNo) { 782 if (lineNumberWriter == null) 783 lineNumberWriter = new DedupLineNumberTableAttribute(constantPool, context); 784 lineNumberWriter.writeLineNumber(curPc(), lineNo); 785 } 786 787 public void setLabelTarget(Label label) { 788 setLabelTarget(label, curPc()); 789 } 790 791 @Override 792 public void setLabelTarget(Label label, int bci) { 793 LabelImpl lab = (LabelImpl) label; 794 if (lab.labelContext() == this) { 795 if (lab.getBCI() != -1) 796 throw new IllegalArgumentException("Setting label target for already-set label"); 797 lab.setBCI(bci); 798 } else { 799 setLabelTarget(lab, bci); 800 } 801 } 802 803 private void setLabelTarget(LabelImpl lab, int bci) { 804 LabelContext context = lab.labelContext(); 805 if (context == mruParent) { 806 mruParentTable[lab.getBCI()] = bci + 1; 807 } 808 else if (context instanceof CodeAttribute parent) { 809 if (parentMap == null) 810 parentMap = new IdentityHashMap<>(); 811 int[] table = parentMap.computeIfAbsent(parent, new Function<CodeAttribute, int[]>() { 812 @Override 813 public int[] apply(CodeAttribute x) { 814 return new int[parent.codeLength() + 1]; 815 } 816 }); 817 818 mruParent = parent; 819 mruParentTable = table; 820 table[lab.getBCI()] = bci + 1; 821 } 822 else if (context instanceof BufferedCodeBuilder) { 823 // Hijack the label 824 lab.setBCI(bci); 825 } 826 else { 827 throw new IllegalStateException(String.format("Unexpected label context %s in =%s", context, this)); 828 } 829 } 830 831 public void addCharacterRange(CharacterRange element) { 832 if (characterRangesCount >= characterRanges.length) { 833 int newCapacity = characterRangesCount + 8; 834 this.characterRanges = Arrays.copyOf(characterRanges, newCapacity); 835 } 836 characterRanges[characterRangesCount++] = element; 837 } 838 839 public void addLabel(DeferredLabel label) { 840 if (deferredLabelsCount >= deferredLabels.length) { 841 int newCapacity = deferredLabelsCount + 8; 842 this.deferredLabels = Arrays.copyOf(deferredLabels, newCapacity); 843 } 844 deferredLabels[deferredLabelsCount++] = label; 845 } 846 847 public void addHandler(ExceptionCatch element) { 848 AbstractPseudoInstruction.ExceptionCatchImpl el = (AbstractPseudoInstruction.ExceptionCatchImpl) element; 849 ClassEntry type = el.catchTypeEntry(); 850 if (type != null && !constantPool.canWriteDirect(type.constantPool())) 851 el = new AbstractPseudoInstruction.ExceptionCatchImpl(element.handler(), element.tryStart(), element.tryEnd(), AbstractPoolEntry.maybeClone(constantPool, type)); 852 handlers.add(el); 853 } 854 855 public void addLocalVariable(LocalVariable element) { 856 if (localVariablesCount >= localVariables.length) { 857 int newCapacity = localVariablesCount + 8; 858 this.localVariables = Arrays.copyOf(localVariables, newCapacity); 859 } 860 localVariables[localVariablesCount++] = element; 861 } 862 863 public void addLocalVariableType(LocalVariableType element) { 864 if (localVariableTypesCount >= localVariableTypes.length) { 865 int newCapacity = localVariableTypesCount + 8; 866 this.localVariableTypes = Arrays.copyOf(localVariableTypes, newCapacity); 867 } 868 localVariableTypes[localVariableTypesCount++] = element; 869 } 870 871 @Override 872 public String toString() { 873 return String.format("CodeBuilder[id=%d]", System.identityHashCode(this)); 874 } 875 876 //ToDo: consolidate and open all exceptions 877 private static final class LabelOverflowException extends IllegalArgumentException { 878 879 private static final long serialVersionUID = 1L; 880 881 public LabelOverflowException() { 882 super("Label target offset overflow"); 883 } 884 } 885 886 // Fast overrides to avoid intermediate instructions 887 // These are helpful for direct class building 888 889 @Override 890 public CodeBuilder return_() { 891 bytecodesBufWriter.writeU1(RETURN); 892 return this; 893 } 894 895 @Override 896 public CodeBuilder return_(TypeKind tk) { 897 bytecodesBufWriter.writeU1(returnBytecode(tk)); 898 return this; 899 } 900 901 @Override 902 public CodeBuilder storeLocal(TypeKind tk, int slot) { 903 return switch (tk) { 904 case INT, SHORT, BYTE, CHAR, BOOLEAN 905 -> istore(slot); 906 case LONG -> lstore(slot); 907 case DOUBLE -> dstore(slot); 908 case FLOAT -> fstore(slot); 909 case REFERENCE -> astore(slot); 910 case VOID -> throw new IllegalArgumentException("void"); 911 }; 912 } 913 914 @Override 915 public CodeBuilder labelBinding(Label label) { 916 setLabelTarget(label, curPc()); 917 return this; 918 } 919 920 @Override 921 public CodeBuilder loadLocal(TypeKind tk, int slot) { 922 return switch (tk) { 923 case INT, SHORT, BYTE, CHAR, BOOLEAN 924 -> iload(slot); 925 case LONG -> lload(slot); 926 case DOUBLE -> dload(slot); 927 case FLOAT -> fload(slot); 928 case REFERENCE -> aload(slot); 929 case VOID -> throw new IllegalArgumentException("void"); 930 }; 931 } 932 933 @Override 934 public CodeBuilder invoke(Opcode opcode, MemberRefEntry ref) { 935 if (opcode == Opcode.INVOKEINTERFACE) { 936 int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.type())) + 1; 937 writeInvokeInterface(opcode, (InterfaceMethodRefEntry) ref, slots); 938 } else { 939 writeInvokeNormal(opcode, ref); 940 } 941 return this; 942 } 943 944 @Override 945 public CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type) { 946 bytecodesBufWriter.writeIndex(INVOKESPECIAL, constantPool().methodRefEntry(owner, name, type)); 947 return this; 948 } 949 950 @Override 951 public CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type) { 952 bytecodesBufWriter.writeIndex(INVOKESTATIC, constantPool().methodRefEntry(owner, name, type)); 953 return this; 954 } 955 956 @Override 957 public CodeBuilder invokevirtual(ClassDesc owner, String name, MethodTypeDesc type) { 958 bytecodesBufWriter.writeIndex(INVOKEVIRTUAL, constantPool().methodRefEntry(owner, name, type)); 959 return this; 960 } 961 962 @Override 963 public CodeBuilder getfield(ClassDesc owner, String name, ClassDesc type) { 964 bytecodesBufWriter.writeIndex(GETFIELD, constantPool().fieldRefEntry(owner, name, type)); 965 return this; 966 } 967 968 @Override 969 public CodeBuilder fieldAccess(Opcode opcode, FieldRefEntry ref) { 970 bytecodesBufWriter.writeIndex(opcode.bytecode(), ref); 971 return this; 972 } 973 974 @Override 975 public CodeBuilder arrayLoad(TypeKind tk) { 976 bytecodesBufWriter.writeU1(BytecodeHelpers.arrayLoadBytecode(tk)); 977 return this; 978 } 979 980 @Override 981 public CodeBuilder arrayStore(TypeKind tk) { 982 bytecodesBufWriter.writeU1(BytecodeHelpers.arrayStoreBytecode(tk)); 983 return this; 984 } 985 986 @Override 987 public CodeBuilder branch(Opcode op, Label target) { 988 writeBranch(op, target); 989 return this; 990 } 991 992 @Override 993 public CodeBuilder nop() { 994 bytecodesBufWriter.writeU1(NOP); 995 return this; 996 } 997 998 @Override 999 public CodeBuilder aconst_null() { 1000 bytecodesBufWriter.writeU1(ACONST_NULL); 1001 return this; 1002 } 1003 1004 @Override 1005 public CodeBuilder aload(int slot) { 1006 if (slot >= 0 && slot <= 3) { 1007 bytecodesBufWriter.writeU1(ALOAD_0 + slot); 1008 } else { 1009 localAccess(ALOAD, slot); 1010 } 1011 return this; 1012 } 1013 1014 @Override 1015 public CodeBuilder anewarray(ClassEntry entry) { 1016 writeNewReferenceArray(entry); 1017 return this; 1018 } 1019 1020 @Override 1021 public CodeBuilder arraylength() { 1022 bytecodesBufWriter.writeU1(ARRAYLENGTH); 1023 return this; 1024 } 1025 1026 @Override 1027 public CodeBuilder areturn() { 1028 bytecodesBufWriter.writeU1(ARETURN); 1029 return this; 1030 } 1031 1032 @Override 1033 public CodeBuilder astore(int slot) { 1034 if (slot >= 0 && slot <= 3) { 1035 bytecodesBufWriter.writeU1(ASTORE_0 + slot); 1036 } else { 1037 localAccess(ASTORE, slot); 1038 } 1039 return this; 1040 } 1041 1042 @Override 1043 public CodeBuilder athrow() { 1044 bytecodesBufWriter.writeU1(ATHROW); 1045 return this; 1046 } 1047 1048 @Override 1049 public CodeBuilder bipush(int b) { 1050 BytecodeHelpers.validateBipush(b); 1051 bytecodesBufWriter.writeU1U1(BIPUSH, b); 1052 return this; 1053 } 1054 1055 @Override 1056 public CodeBuilder checkcast(ClassEntry type) { 1057 bytecodesBufWriter.writeIndex(CHECKCAST, type); 1058 return this; 1059 } 1060 1061 @Override 1062 public CodeBuilder d2f() { 1063 bytecodesBufWriter.writeU1(D2F); 1064 return this; 1065 } 1066 1067 @Override 1068 public CodeBuilder d2i() { 1069 bytecodesBufWriter.writeU1(D2I); 1070 return this; 1071 } 1072 1073 @Override 1074 public CodeBuilder d2l() { 1075 bytecodesBufWriter.writeU1(D2L); 1076 return this; 1077 } 1078 1079 @Override 1080 public CodeBuilder dadd() { 1081 bytecodesBufWriter.writeU1(DADD); 1082 return this; 1083 } 1084 1085 @Override 1086 public CodeBuilder dcmpg() { 1087 bytecodesBufWriter.writeU1(DCMPG); 1088 return this; 1089 } 1090 1091 @Override 1092 public CodeBuilder dcmpl() { 1093 bytecodesBufWriter.writeU1(DCMPL); 1094 return this; 1095 } 1096 1097 @Override 1098 public CodeBuilder dconst_0() { 1099 bytecodesBufWriter.writeU1(DCONST_0); 1100 return this; 1101 } 1102 1103 @Override 1104 public CodeBuilder dconst_1() { 1105 bytecodesBufWriter.writeU1(DCONST_1); 1106 return this; 1107 } 1108 1109 @Override 1110 public CodeBuilder ddiv() { 1111 bytecodesBufWriter.writeU1(DDIV); 1112 return this; 1113 } 1114 1115 @Override 1116 public CodeBuilder dload(int slot) { 1117 if (slot >= 0 && slot <= 3) { 1118 bytecodesBufWriter.writeU1(DLOAD_0 + slot); 1119 } else { 1120 localAccess(DLOAD, slot); 1121 } 1122 return this; 1123 } 1124 1125 @Override 1126 public CodeBuilder dmul() { 1127 bytecodesBufWriter.writeU1(DMUL); 1128 return this; 1129 } 1130 1131 @Override 1132 public CodeBuilder dneg() { 1133 bytecodesBufWriter.writeU1(DNEG); 1134 return this; 1135 } 1136 1137 @Override 1138 public CodeBuilder drem() { 1139 bytecodesBufWriter.writeU1(DREM); 1140 return this; 1141 } 1142 1143 @Override 1144 public CodeBuilder dreturn() { 1145 bytecodesBufWriter.writeU1(DRETURN); 1146 return this; 1147 } 1148 1149 @Override 1150 public CodeBuilder dstore(int slot) { 1151 if (slot >= 0 && slot <= 3) { 1152 bytecodesBufWriter.writeU1(DSTORE_0 + slot); 1153 } else { 1154 localAccess(DSTORE, slot); 1155 } 1156 return this; 1157 } 1158 1159 @Override 1160 public CodeBuilder dsub() { 1161 bytecodesBufWriter.writeU1(DSUB); 1162 return this; 1163 } 1164 1165 @Override 1166 public CodeBuilder dup() { 1167 bytecodesBufWriter.writeU1(DUP); 1168 return this; 1169 } 1170 1171 @Override 1172 public CodeBuilder dup2() { 1173 bytecodesBufWriter.writeU1(DUP2); 1174 return this; 1175 } 1176 1177 @Override 1178 public CodeBuilder dup2_x1() { 1179 bytecodesBufWriter.writeU1(DUP2_X1); 1180 return this; 1181 } 1182 1183 @Override 1184 public CodeBuilder dup2_x2() { 1185 bytecodesBufWriter.writeU1(DUP2_X2); 1186 return this; 1187 } 1188 1189 @Override 1190 public CodeBuilder dup_x1() { 1191 bytecodesBufWriter.writeU1(DUP_X1); 1192 return this; 1193 } 1194 1195 @Override 1196 public CodeBuilder dup_x2() { 1197 bytecodesBufWriter.writeU1(DUP_X2); 1198 return this; 1199 } 1200 1201 @Override 1202 public CodeBuilder f2d() { 1203 bytecodesBufWriter.writeU1(F2D); 1204 return this; 1205 } 1206 1207 @Override 1208 public CodeBuilder f2i() { 1209 bytecodesBufWriter.writeU1(F2I); 1210 return this; 1211 } 1212 1213 @Override 1214 public CodeBuilder f2l() { 1215 bytecodesBufWriter.writeU1(F2L); 1216 return this; 1217 } 1218 1219 @Override 1220 public CodeBuilder fadd() { 1221 bytecodesBufWriter.writeU1(FADD); 1222 return this; 1223 } 1224 1225 @Override 1226 public CodeBuilder fcmpg() { 1227 bytecodesBufWriter.writeU1(FCMPG); 1228 return this; 1229 } 1230 1231 @Override 1232 public CodeBuilder fcmpl() { 1233 bytecodesBufWriter.writeU1(FCMPL); 1234 return this; 1235 } 1236 1237 @Override 1238 public CodeBuilder fconst_0() { 1239 bytecodesBufWriter.writeU1(FCONST_0); 1240 return this; 1241 } 1242 1243 @Override 1244 public CodeBuilder fconst_1() { 1245 bytecodesBufWriter.writeU1(FCONST_1); 1246 return this; 1247 } 1248 1249 @Override 1250 public CodeBuilder fconst_2() { 1251 bytecodesBufWriter.writeU1(FCONST_2); 1252 return this; 1253 } 1254 1255 @Override 1256 public CodeBuilder fdiv() { 1257 bytecodesBufWriter.writeU1(FDIV); 1258 return this; 1259 } 1260 1261 @Override 1262 public CodeBuilder fload(int slot) { 1263 if (slot >= 0 && slot <= 3) { 1264 bytecodesBufWriter.writeU1(FLOAD_0 + slot); 1265 } else { 1266 localAccess(FLOAD, slot); 1267 } 1268 return this; 1269 } 1270 1271 @Override 1272 public CodeBuilder fmul() { 1273 bytecodesBufWriter.writeU1(FMUL); 1274 return this; 1275 } 1276 1277 @Override 1278 public CodeBuilder fneg() { 1279 bytecodesBufWriter.writeU1(FNEG); 1280 return this; 1281 } 1282 1283 @Override 1284 public CodeBuilder frem() { 1285 bytecodesBufWriter.writeU1(FREM); 1286 return this; 1287 } 1288 1289 @Override 1290 public CodeBuilder freturn() { 1291 bytecodesBufWriter.writeU1(FRETURN); 1292 return this; 1293 } 1294 1295 @Override 1296 public CodeBuilder fstore(int slot) { 1297 if (slot >= 0 && slot <= 3) { 1298 bytecodesBufWriter.writeU1(FSTORE_0 + slot); 1299 } else { 1300 localAccess(FSTORE, slot); 1301 } 1302 return this; 1303 } 1304 1305 @Override 1306 public CodeBuilder fsub() { 1307 bytecodesBufWriter.writeU1(FSUB); 1308 return this; 1309 } 1310 1311 @Override 1312 public CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) { 1313 bytecodesBufWriter.writeIndex(GETSTATIC, constantPool().fieldRefEntry(owner, name, type)); 1314 return this; 1315 } 1316 1317 @Override 1318 public CodeBuilder goto_(Label target) { 1319 writeShortJump(GOTO, target); 1320 return this; 1321 } 1322 1323 @Override 1324 public CodeBuilder i2b() { 1325 bytecodesBufWriter.writeU1(I2B); 1326 return this; 1327 } 1328 1329 @Override 1330 public CodeBuilder i2c() { 1331 bytecodesBufWriter.writeU1(I2C); 1332 return this; 1333 } 1334 1335 @Override 1336 public CodeBuilder i2d() { 1337 bytecodesBufWriter.writeU1(I2D); 1338 return this; 1339 } 1340 1341 @Override 1342 public CodeBuilder i2f() { 1343 bytecodesBufWriter.writeU1(I2F); 1344 return this; 1345 } 1346 1347 @Override 1348 public CodeBuilder i2l() { 1349 bytecodesBufWriter.writeU1(I2L); 1350 return this; 1351 } 1352 1353 @Override 1354 public CodeBuilder i2s() { 1355 bytecodesBufWriter.writeU1(I2S); 1356 return this; 1357 } 1358 1359 @Override 1360 public CodeBuilder iadd() { 1361 bytecodesBufWriter.writeU1(IADD); 1362 return this; 1363 } 1364 1365 @Override 1366 public CodeBuilder iand() { 1367 bytecodesBufWriter.writeU1(IAND); 1368 return this; 1369 } 1370 1371 @Override 1372 public CodeBuilder iconst_0() { 1373 bytecodesBufWriter.writeU1(ICONST_0); 1374 return this; 1375 } 1376 1377 @Override 1378 public CodeBuilder iconst_1() { 1379 bytecodesBufWriter.writeU1(ICONST_1); 1380 return this; 1381 } 1382 1383 @Override 1384 public CodeBuilder iconst_2() { 1385 bytecodesBufWriter.writeU1(ICONST_2); 1386 return this; 1387 } 1388 1389 @Override 1390 public CodeBuilder iconst_3() { 1391 bytecodesBufWriter.writeU1(ICONST_3); 1392 return this; 1393 } 1394 1395 @Override 1396 public CodeBuilder iconst_4() { 1397 bytecodesBufWriter.writeU1(ICONST_4); 1398 return this; 1399 } 1400 1401 @Override 1402 public CodeBuilder iconst_5() { 1403 bytecodesBufWriter.writeU1(ICONST_5); 1404 return this; 1405 } 1406 1407 @Override 1408 public CodeBuilder iconst_m1() { 1409 bytecodesBufWriter.writeU1(ICONST_M1); 1410 return this; 1411 } 1412 1413 @Override 1414 public CodeBuilder idiv() { 1415 bytecodesBufWriter.writeU1(IDIV); 1416 return this; 1417 } 1418 1419 @Override 1420 public CodeBuilder if_acmpeq(Label target) { 1421 writeShortJump(IF_ACMPEQ, target); 1422 return this; 1423 } 1424 1425 @Override 1426 public CodeBuilder if_acmpne(Label target) { 1427 writeShortJump(IF_ACMPNE, target); 1428 return this; 1429 } 1430 1431 @Override 1432 public CodeBuilder if_icmpeq(Label target) { 1433 writeShortJump(IF_ICMPEQ, target); 1434 return this; 1435 } 1436 1437 @Override 1438 public CodeBuilder if_icmpge(Label target) { 1439 writeShortJump(IF_ICMPGE, target); 1440 return this; 1441 } 1442 1443 @Override 1444 public CodeBuilder if_icmpgt(Label target) { 1445 writeShortJump(IF_ICMPGT, target); 1446 return this; 1447 } 1448 1449 @Override 1450 public CodeBuilder if_icmple(Label target) { 1451 writeShortJump(IF_ICMPLE, target); 1452 return this; 1453 } 1454 1455 @Override 1456 public CodeBuilder if_icmplt(Label target) { 1457 writeShortJump(IF_ICMPLT, target); 1458 return this; 1459 } 1460 1461 @Override 1462 public CodeBuilder if_icmpne(Label target) { 1463 writeShortJump(IF_ICMPNE, target); 1464 return this; 1465 } 1466 1467 @Override 1468 public CodeBuilder ifnonnull(Label target) { 1469 writeShortJump(IFNONNULL, target); 1470 return this; 1471 } 1472 1473 @Override 1474 public CodeBuilder ifnull(Label target) { 1475 writeShortJump(IFNULL, target); 1476 return this; 1477 } 1478 1479 @Override 1480 public CodeBuilder ifeq(Label target) { 1481 writeShortJump(IFEQ, target); 1482 return this; 1483 } 1484 1485 @Override 1486 public CodeBuilder ifge(Label target) { 1487 writeShortJump(IFGE, target); 1488 return this; 1489 } 1490 1491 @Override 1492 public CodeBuilder ifgt(Label target) { 1493 writeShortJump(IFGT, target); 1494 return this; 1495 } 1496 1497 @Override 1498 public CodeBuilder ifle(Label target) { 1499 writeShortJump(IFLE, target); 1500 return this; 1501 } 1502 1503 @Override 1504 public CodeBuilder iflt(Label target) { 1505 writeShortJump(IFLT, target); 1506 return this; 1507 } 1508 1509 @Override 1510 public CodeBuilder ifne(Label target) { 1511 writeShortJump(IFNE, target); 1512 return this; 1513 } 1514 1515 @Override 1516 public CodeBuilder iinc(int slot, int val) { 1517 writeIncrement(validateAndIsWideIinc(slot, val), slot, val); 1518 return this; 1519 } 1520 1521 @Override 1522 public CodeBuilder iload(int slot) { 1523 if (slot >= 0 && slot <= 3) { 1524 bytecodesBufWriter.writeU1(ILOAD_0 + slot); 1525 } else { 1526 localAccess(ILOAD, slot); 1527 } 1528 return this; 1529 } 1530 1531 @Override 1532 public CodeBuilder imul() { 1533 bytecodesBufWriter.writeU1(IMUL); 1534 return this; 1535 } 1536 1537 @Override 1538 public CodeBuilder ineg() { 1539 bytecodesBufWriter.writeU1(INEG); 1540 return this; 1541 } 1542 1543 @Override 1544 public CodeBuilder instanceOf(ClassEntry target) { 1545 bytecodesBufWriter.writeIndex(INSTANCEOF, target); 1546 return this; 1547 } 1548 1549 @Override 1550 public CodeBuilder invokedynamic(InvokeDynamicEntry ref) { 1551 writeInvokeDynamic(ref); 1552 return this; 1553 } 1554 1555 @Override 1556 public CodeBuilder invokeinterface(InterfaceMethodRefEntry ref) { 1557 writeInvokeInterface(Opcode.INVOKEINTERFACE, ref, Util.parameterSlots(ref.typeSymbol()) + 1); 1558 return this; 1559 } 1560 1561 @Override 1562 public CodeBuilder invokespecial(InterfaceMethodRefEntry ref) { 1563 bytecodesBufWriter.writeIndex(INVOKESPECIAL, ref); 1564 return this; 1565 } 1566 1567 @Override 1568 public CodeBuilder invokespecial(MethodRefEntry ref) { 1569 bytecodesBufWriter.writeIndex(INVOKESPECIAL, ref); 1570 return this; 1571 } 1572 1573 @Override 1574 public CodeBuilder invokestatic(InterfaceMethodRefEntry ref) { 1575 bytecodesBufWriter.writeIndex(INVOKESTATIC, ref); 1576 return this; 1577 } 1578 1579 @Override 1580 public CodeBuilder invokestatic(MethodRefEntry ref) { 1581 bytecodesBufWriter.writeIndex(INVOKESTATIC, ref); 1582 return this; 1583 } 1584 1585 @Override 1586 public CodeBuilder invokevirtual(MethodRefEntry ref) { 1587 bytecodesBufWriter.writeIndex(INVOKEVIRTUAL, ref); 1588 return this; 1589 } 1590 1591 @Override 1592 public CodeBuilder ior() { 1593 bytecodesBufWriter.writeU1(IOR); 1594 return this; 1595 } 1596 1597 @Override 1598 public CodeBuilder irem() { 1599 bytecodesBufWriter.writeU1(IREM); 1600 return this; 1601 } 1602 1603 @Override 1604 public CodeBuilder ireturn() { 1605 bytecodesBufWriter.writeU1(IRETURN); 1606 return this; 1607 } 1608 1609 @Override 1610 public CodeBuilder ishl() { 1611 bytecodesBufWriter.writeU1(ISHL); 1612 return this; 1613 } 1614 1615 @Override 1616 public CodeBuilder ishr() { 1617 bytecodesBufWriter.writeU1(ISHR); 1618 return this; 1619 } 1620 1621 @Override 1622 public CodeBuilder istore(int slot) { 1623 if (slot >= 0 && slot <= 3) { 1624 bytecodesBufWriter.writeU1(ISTORE_0 + slot); 1625 } else { 1626 localAccess(ISTORE, slot); 1627 } 1628 return this; 1629 } 1630 1631 @Override 1632 public CodeBuilder isub() { 1633 bytecodesBufWriter.writeU1(ISUB); 1634 return this; 1635 } 1636 1637 @Override 1638 public CodeBuilder iushr() { 1639 bytecodesBufWriter.writeU1(IUSHR); 1640 return this; 1641 } 1642 1643 @Override 1644 public CodeBuilder ixor() { 1645 bytecodesBufWriter.writeU1(IXOR); 1646 return this; 1647 } 1648 1649 @Override 1650 public CodeBuilder lookupswitch(Label defaultTarget, List<SwitchCase> cases) { 1651 writeLookupSwitch(defaultTarget, cases); 1652 return this; 1653 } 1654 1655 @Override 1656 public CodeBuilder l2d() { 1657 bytecodesBufWriter.writeU1(L2D); 1658 return this; 1659 } 1660 1661 @Override 1662 public CodeBuilder l2f() { 1663 bytecodesBufWriter.writeU1(L2F); 1664 return this; 1665 } 1666 1667 @Override 1668 public CodeBuilder l2i() { 1669 bytecodesBufWriter.writeU1(L2I); 1670 return this; 1671 } 1672 1673 @Override 1674 public CodeBuilder ladd() { 1675 bytecodesBufWriter.writeU1(LADD); 1676 return this; 1677 } 1678 1679 @Override 1680 public CodeBuilder land() { 1681 bytecodesBufWriter.writeU1(LAND); 1682 return this; 1683 } 1684 1685 @Override 1686 public CodeBuilder lcmp() { 1687 bytecodesBufWriter.writeU1(LCMP); 1688 return this; 1689 } 1690 1691 @Override 1692 public CodeBuilder lconst_0() { 1693 bytecodesBufWriter.writeU1(LCONST_0); 1694 return this; 1695 } 1696 1697 @Override 1698 public CodeBuilder lconst_1() { 1699 bytecodesBufWriter.writeU1(LCONST_1); 1700 return this; 1701 } 1702 1703 @Override 1704 public CodeBuilder ldc(LoadableConstantEntry entry) { 1705 var direct = AbstractPoolEntry.maybeClone(constantPool, entry); 1706 writeDirectLoadConstant(BytecodeHelpers.ldcOpcode(direct), direct); 1707 return this; 1708 } 1709 1710 @Override 1711 public CodeBuilder ldiv() { 1712 bytecodesBufWriter.writeU1(LDIV); 1713 return this; 1714 } 1715 1716 @Override 1717 public CodeBuilder lload(int slot) { 1718 if (slot >= 0 && slot <= 3) { 1719 bytecodesBufWriter.writeU1(LLOAD_0 + slot); 1720 } else { 1721 localAccess(LLOAD, slot); 1722 } 1723 return this; 1724 } 1725 1726 @Override 1727 public CodeBuilder lmul() { 1728 bytecodesBufWriter.writeU1(LMUL); 1729 return this; 1730 } 1731 1732 @Override 1733 public CodeBuilder lneg() { 1734 bytecodesBufWriter.writeU1(LNEG); 1735 return this; 1736 } 1737 1738 @Override 1739 public CodeBuilder lor() { 1740 bytecodesBufWriter.writeU1(LOR); 1741 return this; 1742 } 1743 1744 @Override 1745 public CodeBuilder lrem() { 1746 bytecodesBufWriter.writeU1(LREM); 1747 return this; 1748 } 1749 1750 @Override 1751 public CodeBuilder lreturn() { 1752 bytecodesBufWriter.writeU1(LRETURN); 1753 return this; 1754 } 1755 1756 @Override 1757 public CodeBuilder lshl() { 1758 bytecodesBufWriter.writeU1(LSHL); 1759 return this; 1760 } 1761 1762 @Override 1763 public CodeBuilder lshr() { 1764 bytecodesBufWriter.writeU1(LSHR); 1765 return this; 1766 } 1767 1768 @Override 1769 public CodeBuilder lstore(int slot) { 1770 if (slot >= 0 && slot <= 3) { 1771 bytecodesBufWriter.writeU1(LSTORE_0 + slot); 1772 } else { 1773 localAccess(LSTORE, slot); 1774 } 1775 return this; 1776 } 1777 1778 @Override 1779 public CodeBuilder lsub() { 1780 bytecodesBufWriter.writeU1(LSUB); 1781 return this; 1782 } 1783 1784 @Override 1785 public CodeBuilder lushr() { 1786 bytecodesBufWriter.writeU1(LUSHR); 1787 return this; 1788 } 1789 1790 @Override 1791 public CodeBuilder lxor() { 1792 bytecodesBufWriter.writeU1(LXOR); 1793 return this; 1794 } 1795 1796 @Override 1797 public CodeBuilder monitorenter() { 1798 bytecodesBufWriter.writeU1(MONITORENTER); 1799 return this; 1800 } 1801 1802 @Override 1803 public CodeBuilder monitorexit() { 1804 bytecodesBufWriter.writeU1(MONITOREXIT); 1805 return this; 1806 } 1807 1808 @Override 1809 public CodeBuilder multianewarray(ClassEntry array, int dims) { 1810 writeNewMultidimensionalArray(dims, array); 1811 return this; 1812 } 1813 1814 @Override 1815 public CodeBuilder new_(ClassEntry clazz) { 1816 writeNewObject(clazz); 1817 return this; 1818 } 1819 1820 @Override 1821 public CodeBuilder newarray(TypeKind typeKind) { 1822 int atype = typeKind.newarrayCode(); // implicit null check 1823 if (atype < 0) 1824 throw new IllegalArgumentException("Illegal component type: ".concat(typeKind.upperBound().displayName())); 1825 writeNewPrimitiveArray(atype); 1826 return this; 1827 } 1828 1829 @Override 1830 public CodeBuilder pop() { 1831 bytecodesBufWriter.writeU1(POP); 1832 return this; 1833 } 1834 1835 @Override 1836 public CodeBuilder pop2() { 1837 bytecodesBufWriter.writeU1(POP2); 1838 return this; 1839 } 1840 1841 @Override 1842 public CodeBuilder sipush(int s) { 1843 BytecodeHelpers.validateSipush(s); 1844 bytecodesBufWriter.writeU1U2(SIPUSH, s); 1845 return this; 1846 } 1847 1848 @Override 1849 public CodeBuilder swap() { 1850 bytecodesBufWriter.writeU1(SWAP); 1851 return this; 1852 } 1853 1854 @Override 1855 public CodeBuilder tableswitch(int low, int high, Label defaultTarget, List<SwitchCase> cases) { 1856 writeTableSwitch(low, high, defaultTarget, cases); 1857 return this; 1858 } 1859 }