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 DeferredLabel[] EMPTY_LABEL_ARRAY = {};
52 private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {};
53 private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {};
54 private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {};
55 private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {};
56
57 final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers = new ArrayList<>();
58 private CharacterRange[] characterRanges = EMPTY_CHARACTER_RANGE;
59 private LocalVariable[] localVariables = EMPTY_LOCAL_VARIABLE_ARRAY;
60 private LocalVariableType[] localVariableTypes = EMPTY_LOCAL_VARIABLE_TYPE_ARRAY;
61 private int characterRangesCount = 0;
62 private int localVariablesCount = 0;
348 }
349 } else {
350 writeCounters(codeMatch, buf);
351 }
352 }
353
354 @Override
355 public void writeBody(BufWriterImpl buf) {
356 DirectCodeBuilder dcb = DirectCodeBuilder.this;
357 buf.setLabelContext(dcb);
358
359 int codeLength = curPc();
360 if (codeLength == 0 || codeLength >= 65536) {
361 throw new IllegalArgumentException(String.format(
362 "Code length %d is outside the allowed range in %s%s",
363 codeLength,
364 dcb.methodInfo.methodName().stringValue(),
365 dcb.methodInfo.methodTypeSymbol().displayDescriptor()));
366 }
367
368 boolean codeMatch = dcb.original != null && codeAndExceptionsMatch(codeLength);
369 var context = dcb.context;
370 if (context.stackMapsWhenRequired()) {
371 if (codeMatch) {
372 dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null));
373 writeCounters(true, buf);
374 } else {
375 tryGenerateStackMaps(false, buf);
376 }
377 } else if (context.generateStackMaps()) {
378 generateStackMaps(buf);
379 } else if (context.dropStackMaps()) {
380 writeCounters(codeMatch, buf);
381 }
382
383 buf.writeInt(codeLength);
384 buf.writeBytes(dcb.bytecodesBufWriter);
385 dcb.writeExceptionHandlers(buf);
386 dcb.attributes.writeTo(buf);
387 buf.setLabelContext(null);
388 }
426 @Override
427 public void writeBody(BufWriterImpl b) {
428 throw new UnsupportedOperationException();
429 }
430
431 @Override
432 public void writeTo(BufWriterImpl b) {
433 b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE));
434 push();
435 b.writeInt(buf.size() + 2);
436 b.writeU2(buf.size() / 4);
437 b.writeBytes(buf);
438 }
439
440 @Override
441 public Utf8Entry attributeName() {
442 return buf.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
443 }
444 }
445
446 private boolean codeAndExceptionsMatch(int codeLength) {
447 boolean codeAttributesMatch;
448 if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) {
449 codeAttributesMatch = cai.codeLength == curPc()
450 && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength);
451 if (codeAttributesMatch) {
452 var bw = new BufWriterImpl(constantPool, context);
453 writeExceptionHandlers(bw);
454 codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size());
455 }
456 }
457 else
458 codeAttributesMatch = false;
459 return codeAttributesMatch;
460 }
461
462 // Writing support
463
464 private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
465
466 private void processDeferredLabels() {
467 for (int i = 0; i < deferredLabelsCount; i++) {
468 DeferredLabel dl = deferredLabels[i];
469 int branchOffset = labelToBci(dl.label) - dl.instructionPc;
470 if (dl.size == 2) {
471 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
472 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
473 } else {
474 assert dl.size == 4;
475 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 DeferredLabel[] EMPTY_LABEL_ARRAY = {};
53 private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {};
54 private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {};
55 private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {};
56 private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {};
57
58 final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers = new ArrayList<>();
59 private CharacterRange[] characterRanges = EMPTY_CHARACTER_RANGE;
60 private LocalVariable[] localVariables = EMPTY_LOCAL_VARIABLE_ARRAY;
61 private LocalVariableType[] localVariableTypes = EMPTY_LOCAL_VARIABLE_TYPE_ARRAY;
62 private int characterRangesCount = 0;
63 private int localVariablesCount = 0;
349 }
350 } else {
351 writeCounters(codeMatch, buf);
352 }
353 }
354
355 @Override
356 public void writeBody(BufWriterImpl buf) {
357 DirectCodeBuilder dcb = DirectCodeBuilder.this;
358 buf.setLabelContext(dcb);
359
360 int codeLength = curPc();
361 if (codeLength == 0 || codeLength >= 65536) {
362 throw new IllegalArgumentException(String.format(
363 "Code length %d is outside the allowed range in %s%s",
364 codeLength,
365 dcb.methodInfo.methodName().stringValue(),
366 dcb.methodInfo.methodTypeSymbol().displayDescriptor()));
367 }
368
369 boolean codeMatch = dcb.codeAndExceptionsMatch(codeLength, buf);
370 var context = dcb.context;
371 if (context.stackMapsWhenRequired()) {
372 if (codeMatch) {
373 dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null));
374 writeCounters(true, buf);
375 } else {
376 tryGenerateStackMaps(false, buf);
377 }
378 } else if (context.generateStackMaps()) {
379 generateStackMaps(buf);
380 } else if (context.dropStackMaps()) {
381 writeCounters(codeMatch, buf);
382 }
383
384 buf.writeInt(codeLength);
385 buf.writeBytes(dcb.bytecodesBufWriter);
386 dcb.writeExceptionHandlers(buf);
387 dcb.attributes.writeTo(buf);
388 buf.setLabelContext(null);
389 }
427 @Override
428 public void writeBody(BufWriterImpl b) {
429 throw new UnsupportedOperationException();
430 }
431
432 @Override
433 public void writeTo(BufWriterImpl b) {
434 b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE));
435 push();
436 b.writeInt(buf.size() + 2);
437 b.writeU2(buf.size() / 4);
438 b.writeBytes(buf);
439 }
440
441 @Override
442 public Utf8Entry attributeName() {
443 return buf.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
444 }
445 }
446
447 private boolean codeAndExceptionsMatch(int codeLength, BufWriterImpl buf) {
448 boolean codeAttributesMatch;
449 if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) {
450 codeAttributesMatch = cai.codeLength == curPc()
451 && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength);
452 if (codeAttributesMatch) {
453 var bw = new BufWriterImpl(constantPool, context);
454 writeExceptionHandlers(bw);
455 codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size());
456 }
457
458 if (codeAttributesMatch) {
459 var thisIsConstructor = methodInfo.methodName().equalsString(INIT_NAME);
460 var originalIsConstructor = cai.enclosingMethod.methodName().equalsString(INIT_NAME);
461 if (thisIsConstructor || originalIsConstructor) {
462 if (thisIsConstructor != originalIsConstructor) {
463 codeAttributesMatch = false;
464 }
465 }
466
467 if (codeAttributesMatch && thisIsConstructor) {
468 if (!buf.strictFieldsMatch(cai.classReader.getContainedClass())) {
469 codeAttributesMatch = false;
470 }
471 }
472 }
473 }
474 else
475 codeAttributesMatch = false;
476 return codeAttributesMatch;
477 }
478
479 // Writing support
480
481 private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
482
483 private void processDeferredLabels() {
484 for (int i = 0; i < deferredLabelsCount; i++) {
485 DeferredLabel dl = deferredLabels[i];
486 int branchOffset = labelToBci(dl.label) - dl.instructionPc;
487 if (dl.size == 2) {
488 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
489 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
490 } else {
491 assert dl.size == 4;
492 bytecodesBufWriter.patchInt(dl.labelPc, branchOffset);
|