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