23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26 package jdk.internal.classfile.impl;
27
28 import java.lang.classfile.*;
29 import java.lang.classfile.attribute.CodeAttribute;
30 import java.lang.classfile.attribute.LineNumberTableAttribute;
31 import java.lang.classfile.constantpool.*;
32 import java.lang.classfile.instruction.CharacterRange;
33 import java.lang.classfile.instruction.ExceptionCatch;
34 import java.lang.classfile.instruction.LocalVariable;
35 import java.lang.classfile.instruction.LocalVariableType;
36 import java.lang.classfile.instruction.SwitchCase;
37 import java.lang.constant.ClassDesc;
38 import java.lang.constant.MethodTypeDesc;
39 import java.util.*;
40 import java.util.function.Consumer;
41 import java.util.function.Function;
42
43 import static java.util.Objects.requireNonNull;
44 import static jdk.internal.classfile.impl.BytecodeHelpers.*;
45 import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
46
47 public final class DirectCodeBuilder
48 extends AbstractDirectBuilder<CodeModel>
49 implements TerminalCodeBuilder {
50 private static final CharacterRange[] EMPTY_CHARACTER_RANGE = {};
51 private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {};
52 private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {};
53 private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {};
54
55 final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers = new ArrayList<>();
56 private CharacterRange[] characterRanges = EMPTY_CHARACTER_RANGE;
57 private LocalVariable[] localVariables = EMPTY_LOCAL_VARIABLE_ARRAY;
58 private LocalVariableType[] localVariableTypes = EMPTY_LOCAL_VARIABLE_TYPE_ARRAY;
59 private int characterRangesCount = 0;
60 private int localVariablesCount = 0;
61 private int localVariableTypesCount = 0;
62 private final boolean transformDeferredJumps, transformKnownJumps;
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.original != null && codeAndExceptionsMatch(codeLength);
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);
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) {
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 else
467 codeAttributesMatch = false;
468 return codeAttributesMatch;
469 }
470
471 // Writing support
472
473 private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
474
475 private void processDeferredLabels() {
476 for (int i = 0; i < deferredLabelsCount; i++) {
477 DeferredLabel dl = deferredLabels[i];
478 int branchOffset = labelToBci(dl.label) - dl.instructionPc;
479 if (dl.size == 2) {
480 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
481 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
482 } else {
483 assert dl.size == 4;
484 bytecodesBufWriter.patchInt(dl.labelPc, branchOffset);
|
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;
357 }
358 }
359 } else {
360 writeCounters(codeMatch, buf);
361 }
362 }
363
364 @Override
365 public void writeBody(BufWriterImpl buf) {
366 DirectCodeBuilder dcb = DirectCodeBuilder.this;
367
368 int codeLength = curPc();
369 if (codeLength == 0 || codeLength >= 65536) {
370 throw new IllegalArgumentException(String.format(
371 "Code length %d is outside the allowed range in %s%s",
372 codeLength,
373 dcb.methodInfo.methodName().stringValue(),
374 dcb.methodInfo.methodTypeSymbol().displayDescriptor()));
375 }
376
377 boolean codeMatch = dcb.codeAndExceptionsMatch(codeLength, buf);
378 buf.setLabelContext(dcb, codeMatch);
379 var context = dcb.context;
380 if (context.stackMapsWhenRequired()) {
381 if (codeMatch) {
382 dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null));
383 writeCounters(true, buf);
384 } else {
385 tryGenerateStackMaps(false, buf);
386 }
387 } else if (context.generateStackMaps()) {
388 generateStackMaps(buf);
389 } else if (context.dropStackMaps()) {
390 writeCounters(codeMatch, buf);
391 }
392
393 buf.writeInt(codeLength);
394 buf.writeBytes(dcb.bytecodesBufWriter);
395 dcb.writeExceptionHandlers(buf);
396 dcb.attributes.writeTo(buf);
397 buf.setLabelContext(null, false);
436 @Override
437 public void writeBody(BufWriterImpl b) {
438 throw new UnsupportedOperationException();
439 }
440
441 @Override
442 public void writeTo(BufWriterImpl b) {
443 b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE));
444 push();
445 b.writeInt(buf.size() + 2);
446 b.writeU2(buf.size() / 4);
447 b.writeBytes(buf);
448 }
449
450 @Override
451 public Utf8Entry attributeName() {
452 return buf.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
453 }
454 }
455
456 private boolean codeAndExceptionsMatch(int codeLength, BufWriterImpl buf) {
457 boolean codeAttributesMatch;
458 if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) {
459 codeAttributesMatch = cai.codeLength == curPc()
460 && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength);
461 if (codeAttributesMatch) {
462 var bw = new BufWriterImpl(constantPool, context);
463 writeExceptionHandlers(bw);
464 codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size());
465 }
466
467 if (codeAttributesMatch) {
468 var thisIsConstructor = methodInfo.methodName().equalsString(INIT_NAME);
469 var originalIsConstructor = cai.enclosingMethod.methodName().equalsString(INIT_NAME);
470 if (thisIsConstructor || originalIsConstructor) {
471 if (thisIsConstructor != originalIsConstructor) {
472 codeAttributesMatch = false;
473 }
474 }
475
476 if (codeAttributesMatch && thisIsConstructor) {
477 if (!buf.strictFieldsMatch(cai.classReader.getContainedClass())) {
478 codeAttributesMatch = false;
479 }
480 }
481 }
482 }
483 else
484 codeAttributesMatch = false;
485 return codeAttributesMatch;
486 }
487
488 // Writing support
489
490 private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
491
492 private void processDeferredLabels() {
493 for (int i = 0; i < deferredLabelsCount; i++) {
494 DeferredLabel dl = deferredLabels[i];
495 int branchOffset = labelToBci(dl.label) - dl.instructionPc;
496 if (dl.size == 2) {
497 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
498 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
499 } else {
500 assert dl.size == 4;
501 bytecodesBufWriter.patchInt(dl.labelPc, branchOffset);
|