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