< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

@@ -30,31 +30,22 @@
  import com.sun.tools.javac.resources.CompilerProperties.Errors;
  import com.sun.tools.javac.util.*;
  import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  
  import java.util.function.ToIntBiFunction;
- import java.util.function.ToIntFunction;
  
  import static com.sun.tools.javac.code.TypeTag.BOT;
  import static com.sun.tools.javac.code.TypeTag.DOUBLE;
  import static com.sun.tools.javac.code.TypeTag.INT;
  import static com.sun.tools.javac.code.TypeTag.LONG;
  import static com.sun.tools.javac.jvm.ByteCodes.*;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
  import static com.sun.tools.javac.jvm.UninitializedType.*;
  import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
  import java.util.Arrays;
+ import java.util.Map;
+ import java.util.HashMap;
+ import java.util.Set;
  
  /** An internal structure that corresponds to the code attribute of
   *  methods in a classfile. The class also provides some utility operations to
   *  generate bytecode instructions.
   *

@@ -195,10 +186,18 @@
  
      final MethodSymbol meth;
  
      private int letExprStackPos = 0;
  
+     private Map<Integer, Set<VarSymbol>> cpToUnsetFieldsMap = new HashMap<>();
+ 
+     public Set<VarSymbol> initialUnsetFields;
+ 
+     public Set<VarSymbol> currentUnsetFields;
+ 
+     boolean generateEarlyLarvalFrame;
+ 
      /** Construct a code object, given the settings of the fatcode,
       *  debugging info switches and the CharacterRangeTable.
       */
      public Code(MethodSymbol meth,
                  boolean fatcode,

@@ -207,11 +206,12 @@
                  StackMapFormat stackMap,
                  boolean debugCode,
                  CRTable crt,
                  Symtab syms,
                  Types types,
-                 PoolWriter poolWriter) {
+                 PoolWriter poolWriter,
+                 boolean generateEarlyLarvalFrame) {
          this.meth = meth;
          this.fatcode = fatcode;
          this.lineMap = lineMap;
          this.lineDebugInfo = lineMap != null;
          this.varDebugInfo = varDebugInfo;

@@ -229,10 +229,11 @@
          default:
              this.needStackMap = false;
          }
          state = new State();
          lvar = new LocalVar[20];
+         this.generateEarlyLarvalFrame = generateEarlyLarvalFrame;
      }
  
  
  /* **************************************************************************
   * Typecodes & related stuff

@@ -1079,11 +1080,10 @@
          default:
              throw new AssertionError(mnem(op));
          }
          // postop();
      }
- 
      /** Emit an opcode with a four-byte operand field.
       */
      public void emitop4(int op, int od) {
          emitop(op);
          if (!alive) return;

@@ -1226,10 +1226,11 @@
      /** An entry in the stack map. */
      static class StackMapFrame {
          int pc;
          Type[] locals;
          Type[] stack;
+         Set<VarSymbol> unsetFields;
      }
  
      /** A buffer of cldc stack map entries. */
      StackMapFrame[] stackMapBuffer = null;
  

@@ -1321,17 +1322,21 @@
          }
  
          StackMapFrame frame = new StackMapFrame();
          frame.pc = pc;
  
+         boolean hasUninitalizedThis = false;
          int localCount = 0;
          Type[] locals = new Type[localsSize];
          for (int i=0; i<localsSize; i++, localCount++) {
              if (state.defined.isMember(i) && lvar[i] != null) {
                  Type vtype = lvar[i].sym.type;
-                 if (!(vtype instanceof UninitializedType))
+                 if (!(vtype instanceof UninitializedType)) {
                      vtype = types.erasure(vtype);
+                 } else if (vtype.hasTag(TypeTag.UNINITIALIZED_THIS)) {
+                     hasUninitalizedThis = true;
+                 }
                  locals[i] = vtype;
                  if (width(vtype) > 1) i++;
              }
          }
          frame.locals = new Type[localCount];

@@ -1353,24 +1358,39 @@
              if (state.stack[i] != null) {
                  frame.stack[stackCount++] = types.erasure(state.stack[i]);
              }
          }
  
+         Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc);
+         boolean encloseWithEarlyLarvalFrame = unsetFieldsAtPC != null && generateEarlyLarvalFrame && hasUninitalizedThis
+                 && !lastFrame.unsetFields.equals(unsetFieldsAtPC);
+ 
          if (stackMapTableBuffer == null) {
              stackMapTableBuffer = new StackMapTableFrame[20];
          } else {
              stackMapTableBuffer = ArrayUtils.ensureCapacity(
                                      stackMapTableBuffer,
                                      stackMapBufferSize);
          }
-         stackMapTableBuffer[stackMapBufferSize++] =
-                 StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types);
+ 
+         StackMapTableFrame tableFrame = StackMapTableFrame.getInstance(frame, lastFrame, types, pc);
+         if (encloseWithEarlyLarvalFrame) {
+             tableFrame = new StackMapTableFrame.EarlyLarvalFrame(tableFrame, unsetFieldsAtPC);
+             frame.unsetFields = unsetFieldsAtPC;
+         } else {
+             frame.unsetFields = lastFrame.unsetFields;
+         }
+         stackMapTableBuffer[stackMapBufferSize++] = tableFrame;
  
          frameBeforeLast = lastFrame;
          lastFrame = frame;
      }
  
+     public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) {
+         cpToUnsetFieldsMap.put(pc, unsetFields);
+     }
+ 
      StackMapFrame getInitialFrame() {
          StackMapFrame frame = new StackMapFrame();
          List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
          int len = arg_types.length();
          int count = 0;

@@ -1388,10 +1408,11 @@
          for (Type arg_type : arg_types) {
              frame.locals[count++] = types.erasure(arg_type);
          }
          frame.pc = -1;
          frame.stack = null;
+         frame.unsetFields = initialUnsetFields;
          return frame;
      }
  
  
  /* ************************************************************************

@@ -1466,10 +1487,13 @@
          }
          if (opcode != dontgoto && isAlive()) {
              result = new Chain(emitJump(opcode),
                                 result,
                                 state.dup());
+             if (currentUnsetFields != null) {
+                 addUnsetFieldsAtPC(result.pc, currentUnsetFields);
+             }
              fixedPc = fatcode;
              if (opcode == goto_) alive = false;
          }
          return result;
      }

@@ -1477,10 +1501,11 @@
      /** Resolve chain to point to given target.
       */
      public void resolve(Chain chain, int target) {
          boolean changed = false;
          State newState = state;
+         int originalTarget = target;
          for (; chain != null; chain = chain.next) {
              Assert.check(state != chain.state
                      && (target > chain.pc || isStatementStart()));
              if (target >= cp) {
                  target = cp;

@@ -1503,17 +1528,25 @@
                      // from the instruction before goto_.
                      alive = true;
                      break;
                  }
              } else {
-                 if (fatcode)
+                 if (fatcode) {
                      put4(chain.pc + 1, target - chain.pc);
+                     if (cpToUnsetFieldsMap.get(chain.pc) != null) {
+                         addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
+                     }
+                 }
                  else if (target - chain.pc < Short.MIN_VALUE ||
                           target - chain.pc > Short.MAX_VALUE)
                      fatcode = true;
-                 else
+                 else {
                      put2(chain.pc + 1, target - chain.pc);
+                     if (cpToUnsetFieldsMap.get(chain.pc) != null) {
+                         addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
+                     }
+                 }
                  Assert.check(!alive ||
                      chain.state.stacksize == newState.stacksize &&
                      chain.state.nlocks == newState.nlocks);
              }
              fixedPc = true;
< prev index next >