< prev index next >

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

Print this page
@@ -30,30 +30,18 @@
  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.ARRAY;
  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.code.TypeTag.TYPEVAR;
+ import static com.sun.tools.javac.code.TypeTag.UNINITIALIZED_THIS;
  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;
  
  /** An internal structure that corresponds to the code attribute of

@@ -197,10 +185,16 @@
  
      final MethodSymbol meth;
  
      private int letExprStackPos = 0;
  
+     /** The initial unset strict fields in this method frame
+      */
+     public List<VarSymbol> initialUnsetFields = List.nil();
+ 
+     boolean generateEarlyLarvalFrame;
+ 
      /** Construct a code object, given the settings of the fatcode,
       *  debugging info switches and the CharacterRangeTable.
       */
      public Code(MethodSymbol meth,
                  boolean fatcode,

@@ -209,11 +203,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;

@@ -231,10 +226,21 @@
          default:
              this.needStackMap = false;
          }
          state = new State();
          lvar = new LocalVar[20];
+         this.generateEarlyLarvalFrame = generateEarlyLarvalFrame;
+     }
+ 
+     void initUnsetStrictFields(ClassSymbol csym) {
+         int strictFieldOffset = 0;
+         for (Symbol s : csym.members().getSymbols(Symbol::isStrictInstance)) {
+             VarSymbol strictField = (VarSymbol)s;
+             strictField.adr = strictFieldOffset++;
+             initialUnsetFields = initialUnsetFields.prepend(strictField); // lookup returns symbols in reversed order
+             state.unsetStrict.incl(strictField.adr);
+         }
      }
  
  
  /* **************************************************************************
   * Typecodes & related stuff

@@ -1054,11 +1060,17 @@
              break;
          case goto_:
              markDead();
              break;
          case putfield:
-             state.pop(((Symbol)data).erasure(types));
+             VarSymbol field = (VarSymbol)data;
+             state.pop(field.erasure(types));
+             if (field.isStrictInstance() &&
+                     field.owner == meth.owner &&
+                     state.peek().hasTag(UNINITIALIZED_THIS)) {
+                 state.unsetStrict.excl(field.adr);
+             }
              state.pop(1); // object ref
              break;
          case getfield:
              state.pop(1); // object ref
              state.push(((Symbol)data).erasure(types));

@@ -1081,11 +1093,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;

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

@@ -1323,17 +1335,21 @@
          }
  
          StackMapFrame frame = new StackMapFrame();
          frame.pc = pc;
  
+         boolean hasUninitializedThis = 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)) {
+                     hasUninitializedThis = true;
+                 }
                  locals[i] = vtype;
                  if (width(vtype) > 1) i++;
              }
          }
          frame.locals = new Type[localCount];

@@ -1355,24 +1371,41 @@
              if (state.stack[i] != null) {
                  frame.stack[stackCount++] = types.erasure(state.stack[i]);
              }
          }
  
+         List<VarSymbol> unsetStrictFields = collectUnsetStrictFields();
+         boolean encloseWithEarlyLarvalFrame = generateEarlyLarvalFrame && hasUninitializedThis
+                 && !lastFrame.unsetFields.equals(unsetStrictFields);
+ 
          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, unsetStrictFields);
+             frame.unsetFields = unsetStrictFields;
+         } else {
+             frame.unsetFields = lastFrame.unsetFields;
+         }
+         stackMapTableBuffer[stackMapBufferSize++] = tableFrame;
  
          frameBeforeLast = lastFrame;
          lastFrame = frame;
      }
  
+     List<VarSymbol> collectUnsetStrictFields() {
+         return initialUnsetFields.stream()
+                 .filter(s -> state.unsetStrict.isMember(s.adr))
+                 .collect(List.collector());
+     }
+ 
      StackMapFrame getInitialFrame() {
          StackMapFrame frame = new StackMapFrame();
          List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
          int len = arg_types.length();
          int count = 0;

@@ -1390,10 +1423,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;
      }
  
  
  /* ************************************************************************

@@ -1479,10 +1513,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;

@@ -1505,17 +1540,19 @@
                      // from the instruction before goto_.
                      alive = true;
                      break;
                  }
              } else {
-                 if (fatcode)
+                 if (fatcode) {
                      put4(chain.pc + 1, target - 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);
+                 }
                  Assert.check(!alive ||
                      chain.state.stacksize == newState.stacksize &&
                      chain.state.nlocks == newState.nlocks);
              }
              fixedPc = true;

@@ -1655,10 +1692,13 @@
  
      class State implements Cloneable {
          /** The set of registers containing values. */
          Bits defined;
  
+         /** The unset strict fields. */
+         Bits unsetStrict;
+ 
          /** The (types of the) contents of the machine stack. */
          Type[] stack;
  
          /** The first stack position currently unused. */
          int stacksize;

@@ -1667,17 +1707,19 @@
          int[] locks;
          int nlocks;
  
          State() {
              defined = new Bits();
+             unsetStrict = new Bits();
              stack = new Type[16];
          }
  
          State dup() {
              try {
                  State state = (State)super.clone();
                  state.defined = new Bits(defined);
+                 state.unsetStrict = new Bits(unsetStrict);
                  state.stack = stack.clone();
                  if (locks != null) state.locks = locks.clone();
                  if (debugCode) {
                      System.err.println("duping state " + this);
                      dump();

@@ -1802,10 +1844,11 @@
              }
          }
  
          State join(State other) {
              defined.andSet(other.defined);
+             unsetStrict.orSet(other.unsetStrict);
              Assert.check(stacksize == other.stacksize
                      && nlocks == other.nlocks);
              for (int i=0; i<stacksize; ) {
                  Type t = stack[i];
                  Type tother = other.stack[i];
< prev index next >