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