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