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