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;
358 }
359 }
360 } else {
361 writeCounters(codeMatch, buf);
362 }
363 }
364
365 @Override
366 public void writeBody(BufWriterImpl buf) {
367 DirectCodeBuilder dcb = DirectCodeBuilder.this;
368
369 int codeLength = curPc();
370 if (codeLength == 0 || codeLength >= 65536) {
371 throw new IllegalArgumentException(String.format(
372 "Code length %d is outside the allowed range in %s%s",
373 codeLength,
374 dcb.methodInfo.methodName().stringValue(),
375 dcb.methodInfo.methodTypeSymbol().displayDescriptor()));
376 }
377
378 boolean codeMatch = dcb.original != null && codeAndExceptionsMatch(codeLength);
379 buf.setLabelContext(dcb, codeMatch);
380 var context = dcb.context;
381 if (context.stackMapsWhenRequired()) {
382 if (codeMatch) {
383 dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null));
384 writeCounters(true, buf);
385 } else {
386 tryGenerateStackMaps(false, buf);
387 }
388 } else if (context.generateStackMaps()) {
389 generateStackMaps(buf);
390 } else if (context.dropStackMaps()) {
391 writeCounters(codeMatch, buf);
392 }
393
394 buf.writeInt(codeLength);
395 buf.writeBytes(dcb.bytecodesBufWriter);
396 dcb.writeExceptionHandlers(buf);
397 dcb.attributes.writeTo(buf);
398 buf.setLabelContext(null, false);
437 @Override
438 public void writeBody(BufWriterImpl b) {
439 throw new UnsupportedOperationException();
440 }
441
442 @Override
443 public void writeTo(BufWriterImpl b) {
444 b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE));
445 push();
446 b.writeInt(buf.size() + 2);
447 b.writeU2(Util.checkU2(buf.size() / 4, "line number count"));
448 b.writeBytes(buf);
449 }
450
451 @Override
452 public Utf8Entry attributeName() {
453 return buf.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
454 }
455 }
456
457 private boolean codeAndExceptionsMatch(int codeLength) {
458 boolean codeAttributesMatch;
459 if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) {
460 codeAttributesMatch = cai.codeLength == curPc()
461 && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength);
462 if (codeAttributesMatch) {
463 var bw = new BufWriterImpl(constantPool, context);
464 writeExceptionHandlers(bw);
465 codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size());
466 }
467 }
468 else
469 codeAttributesMatch = false;
470 return codeAttributesMatch;
471 }
472
473 // Writing support
474
475 private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
476
477 private void processDeferredLabels() {
478 for (int i = 0; i < deferredLabelsCount; i++) {
479 DeferredLabel dl = deferredLabels[i];
480 int branchOffset = labelToBci(dl.label) - dl.instructionPc;
481 if (dl.size == 2) {
482 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
483 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
484 } else {
485 assert dl.size == 4;
486 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;
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);
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);
|