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