< 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;

 355                         }
 356                     }
 357                 } else {
 358                     writeCounters(codeMatch, buf);
 359                 }
 360             }
 361 
 362             @Override
 363             public void writeBody(BufWriterImpl buf) {
 364                 DirectCodeBuilder dcb = DirectCodeBuilder.this;
 365 
 366                 int codeLength = curPc();
 367                 if (codeLength == 0 || codeLength >= 65536) {
 368                     throw new IllegalArgumentException(String.format(
 369                             "Code length %d is outside the allowed range in %s%s",
 370                             codeLength,
 371                             dcb.methodInfo.methodName().stringValue(),
 372                             dcb.methodInfo.methodTypeSymbol().displayDescriptor()));
 373                 }
 374 
 375                 boolean codeMatch = dcb.original != null && codeAndExceptionsMatch(codeLength);
 376                 buf.setLabelContext(dcb, codeMatch);
 377                 var context = dcb.context;
 378                 if (context.stackMapsWhenRequired()) {
 379                     if (codeMatch) {
 380                         dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null));
 381                         writeCounters(true, buf);
 382                     } else {
 383                         tryGenerateStackMaps(false, buf);
 384                     }
 385                 } else if (context.generateStackMaps()) {
 386                     generateStackMaps(buf);
 387                 } else if (context.dropStackMaps()) {
 388                     writeCounters(codeMatch, buf);
 389                 }
 390 
 391                 buf.writeInt(codeLength);
 392                 buf.writeBytes(dcb.bytecodesBufWriter);
 393                 dcb.writeExceptionHandlers(buf);
 394                 dcb.attributes.writeTo(buf);
 395                 buf.setLabelContext(null, false);

 434         @Override
 435         public void writeBody(BufWriterImpl b) {
 436             throw new UnsupportedOperationException();
 437         }
 438 
 439         @Override
 440         public void writeTo(BufWriterImpl b) {
 441             b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE));
 442             push();
 443             b.writeInt(buf.size() + 2);
 444             b.writeU2(buf.size() / 4);
 445             b.writeBytes(buf);
 446         }
 447 
 448         @Override
 449         public Utf8Entry attributeName() {
 450             return buf.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE);
 451         }
 452     }
 453 
 454     private boolean codeAndExceptionsMatch(int codeLength) {
 455         boolean codeAttributesMatch;
 456         if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) {
 457             codeAttributesMatch = cai.codeLength == curPc()
 458                                   && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength);
 459             if (codeAttributesMatch) {
 460                 var bw = new BufWriterImpl(constantPool, context);
 461                 writeExceptionHandlers(bw);
 462                 codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size());
 463             }
















 464         }
 465         else
 466             codeAttributesMatch = false;
 467         return codeAttributesMatch;
 468     }
 469 
 470     // Writing support
 471 
 472     private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
 473 
 474     private void processDeferredLabels() {
 475         for (int i = 0; i < deferredLabelsCount; i++) {
 476             DeferredLabel dl = deferredLabels[i];
 477             int branchOffset = labelToBci(dl.label) - dl.instructionPc;
 478             if (dl.size == 2) {
 479                 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
 480                 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
 481             } else {
 482                 assert dl.size == 4;
 483                 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;

 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.codeAndExceptionsMatch(codeLength, buf);
 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, BufWriterImpl buf) {
 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             if (codeAttributesMatch) {
 467                 var thisIsConstructor = methodInfo.methodName().equalsString(INIT_NAME);
 468                 var originalIsConstructor = cai.enclosingMethod.methodName().equalsString(INIT_NAME);
 469                 if (thisIsConstructor || originalIsConstructor) {
 470                     if (thisIsConstructor != originalIsConstructor) {
 471                         codeAttributesMatch = false;
 472                     }
 473                 }
 474 
 475                 if (codeAttributesMatch && thisIsConstructor) {
 476                     if (!buf.strictFieldsMatch(cai.classReader.getContainedClass())) {
 477                         codeAttributesMatch = false;
 478                     }
 479                 }
 480             }
 481         }
 482         else
 483             codeAttributesMatch = false;
 484         return codeAttributesMatch;
 485     }
 486 
 487     // Writing support
 488 
 489     private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
 490 
 491     private void processDeferredLabels() {
 492         for (int i = 0; i < deferredLabelsCount; i++) {
 493             DeferredLabel dl = deferredLabels[i];
 494             int branchOffset = labelToBci(dl.label) - dl.instructionPc;
 495             if (dl.size == 2) {
 496                 if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
 497                 bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
 498             } else {
 499                 assert dl.size == 4;
 500                 bytecodesBufWriter.patchInt(dl.labelPc, branchOffset);
< prev index next >