< prev index next >

src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java

Print this page

  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);
< prev index next >