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