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