< prev index next >

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

Print this page
*** 30,30 ***
  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.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
--- 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 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.UNINITIALIZED_THIS;
  import static com.sun.tools.javac.jvm.ByteCodes.*;
  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 ***
                  StackMapFormat stackMap,
                  boolean debugCode,
                  CRTable crt,
                  Symtab syms,
                  Types types,
!                 PoolWriter poolWriter) {
          this.meth = meth;
          this.fatcode = fatcode;
          this.lineMap = lineMap;
          this.lineDebugInfo = lineMap != null;
          this.varDebugInfo = varDebugInfo;
--- 203,12 ---
                  StackMapFormat stackMap,
                  boolean debugCode,
                  CRTable crt,
                  Symtab syms,
                  Types types,
!                 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 ***
              break;
          case goto_:
              markDead();
              break;
          case putfield:
!             state.pop(((Symbol)data).erasure(types));
              state.pop(1); // object ref
              break;
          case getfield:
              state.pop(1); // object ref
              state.push(((Symbol)data).erasure(types));
--- 1060,17 ---
              break;
          case goto_:
              markDead();
              break;
          case putfield:
!             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 ***
          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;
--- 1093,10 ---

*** 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 ***
          }
  
          StackMapFrame frame = new StackMapFrame();
          frame.pc = pc;
  
          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))
                      vtype = types.erasure(vtype);
                  locals[i] = vtype;
                  if (width(vtype) > 1) i++;
              }
          }
          frame.locals = new Type[localCount];
--- 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)) {
                      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 ***
              if (state.stack[i] != null) {
                  frame.stack[stackCount++] = types.erasure(state.stack[i]);
              }
          }
  
          if (stackMapTableBuffer == null) {
              stackMapTableBuffer = new StackMapTableFrame[20];
          } else {
              stackMapTableBuffer = ArrayUtils.ensureCapacity(
                                      stackMapTableBuffer,
                                      stackMapBufferSize);
          }
!         stackMapTableBuffer[stackMapBufferSize++] =
!                 StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types);
  
          frameBeforeLast = lastFrame;
          lastFrame = frame;
      }
  
      StackMapFrame getInitialFrame() {
          StackMapFrame frame = new StackMapFrame();
          List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
          int len = arg_types.length();
          int count = 0;
--- 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);
          }
! 
!         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 ***
                      // from the instruction before goto_.
                      alive = true;
                      break;
                  }
              } else {
!                 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
                      put2(chain.pc + 1, target - chain.pc);
                  Assert.check(!alive ||
                      chain.state.stacksize == newState.stacksize &&
                      chain.state.nlocks == newState.nlocks);
              }
              fixedPc = true;
--- 1540,19 ---
                      // from the instruction before goto_.
                      alive = true;
                      break;
                  }
              } else {
!                 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 {
                      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 >