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