< prev index next >

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

Print this page

  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import com.sun.tools.javac.code.*;
  29 import com.sun.tools.javac.code.Symbol.*;
  30 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  31 import com.sun.tools.javac.util.*;
  32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  33 
  34 import java.util.function.ToIntBiFunction;
  35 import java.util.function.ToIntFunction;
  36 
  37 import static com.sun.tools.javac.code.TypeTag.ARRAY;
  38 import static com.sun.tools.javac.code.TypeTag.BOT;
  39 import static com.sun.tools.javac.code.TypeTag.DOUBLE;
  40 import static com.sun.tools.javac.code.TypeTag.INT;
  41 import static com.sun.tools.javac.code.TypeTag.LONG;
  42 import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
  43 import static com.sun.tools.javac.jvm.ByteCodes.*;
  44 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
  45 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
  46 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
  47 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
  48 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
  49 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
  50 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
  51 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
  52 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
  53 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
  54 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
  55 import static com.sun.tools.javac.jvm.UninitializedType.*;
  56 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
  57 import java.util.Arrays;



  58 
  59 /** An internal structure that corresponds to the code attribute of
  60  *  methods in a classfile. The class also provides some utility operations to
  61  *  generate bytecode instructions.
  62  *
  63  *  <p><b>This is NOT part of any supported API.
  64  *  If you write code that depends on this, you do so at your own risk.
  65  *  This code and its internal interfaces are subject to change or
  66  *  deletion without notice.</b>
  67  */
  68 public class Code {
  69 
  70     public final boolean debugCode;
  71     public final boolean needStackMap;
  72 
  73     public enum StackMapFormat {
  74         NONE,
  75         CLDC {
  76             Name getAttributeName(Names names) {
  77                 return names.StackMap;

 182 
 183     /** The stack map format to be generated. */
 184     StackMapFormat stackMap;
 185 
 186     /** Switch: emit variable debug info.
 187      */
 188     boolean varDebugInfo;
 189 
 190     /** Switch: emit line number info.
 191      */
 192     boolean lineDebugInfo;
 193 
 194     /** Emit line number info if map supplied
 195      */
 196     Position.LineMap lineMap;
 197 
 198     final MethodSymbol meth;
 199 
 200     private int letExprStackPos = 0;
 201 








 202     /** Construct a code object, given the settings of the fatcode,
 203      *  debugging info switches and the CharacterRangeTable.
 204      */
 205     public Code(MethodSymbol meth,
 206                 boolean fatcode,
 207                 Position.LineMap lineMap,
 208                 boolean varDebugInfo,
 209                 StackMapFormat stackMap,
 210                 boolean debugCode,
 211                 CRTable crt,
 212                 Symtab syms,
 213                 Types types,
 214                 PoolWriter poolWriter) {

 215         this.meth = meth;
 216         this.fatcode = fatcode;
 217         this.lineMap = lineMap;
 218         this.lineDebugInfo = lineMap != null;
 219         this.varDebugInfo = varDebugInfo;
 220         this.crt = crt;
 221         this.syms = syms;
 222         this.types = types;
 223         this.poolWriter = poolWriter;
 224         this.debugCode = debugCode;
 225         this.stackMap = stackMap;
 226         switch (stackMap) {
 227         case CLDC:
 228         case JSR202:
 229             this.needStackMap = true;
 230             break;
 231         default:
 232             this.needStackMap = false;
 233         }
 234         state = new State();
 235         lvar = new LocalVar[20];

 236     }
 237 
 238 
 239 /* **************************************************************************
 240  * Typecodes & related stuff
 241  ****************************************************************************/
 242 
 243     /** Given a type, return its type code (used implicitly in the
 244      *  JVM architecture).
 245      */
 246     public static int typecode(Type type) {
 247         switch (type.getTag()) {
 248         case BYTE: return BYTEcode;
 249         case SHORT: return SHORTcode;
 250         case CHAR: return CHARcode;
 251         case INT: return INTcode;
 252         case LONG: return LONGcode;
 253         case FLOAT: return FLOATcode;
 254         case DOUBLE: return DOUBLEcode;
 255         case BOOLEAN: return BYTEcode;

1066         case checkcast: {
1067             state.pop(1); // object ref
1068             Type t = types.erasure((Type)data);
1069             state.push(t);
1070             break; }
1071         case ldc2:
1072         case ldc2w:
1073             state.push(types.constantType((LoadableConstant)data));
1074             break;
1075         case instanceof_:
1076             state.pop(1);
1077             state.push(syms.intType);
1078             break;
1079         case jsr:
1080             break;
1081         default:
1082             throw new AssertionError(mnem(op));
1083         }
1084         // postop();
1085     }
1086 
1087     /** Emit an opcode with a four-byte operand field.
1088      */
1089     public void emitop4(int op, int od) {
1090         emitop(op);
1091         if (!alive) return;
1092         emit4(od);
1093         switch (op) {
1094         case goto_w:
1095             markDead();
1096             break;
1097         case jsr_w:
1098             break;
1099         default:
1100             throw new AssertionError(mnem(op));
1101         }
1102         // postop();
1103     }
1104 
1105     /** Align code pointer to next `incr' boundary.
1106      */

1213 
1214     public int setLetExprStackPos(int pos) {
1215         int res = letExprStackPos;
1216         letExprStackPos = pos;
1217         return res;
1218     }
1219 
1220     public boolean isStatementStart() {
1221         return !alive || state.stacksize == letExprStackPos;
1222     }
1223 
1224 /* ************************************************************************
1225  * Stack map generation
1226  *************************************************************************/
1227 
1228     /** An entry in the stack map. */
1229     static class StackMapFrame {
1230         int pc;
1231         Type[] locals;
1232         Type[] stack;

1233     }
1234 
1235     /** A buffer of cldc stack map entries. */
1236     StackMapFrame[] stackMapBuffer = null;
1237 
1238     /** A buffer of compressed StackMapTable entries. */
1239     StackMapTableFrame[] stackMapTableBuffer = null;
1240     int stackMapBufferSize = 0;
1241 
1242     /** The last PC at which we generated a stack map. */
1243     int lastStackMapPC = -1;
1244 
1245     /** The last stack map frame in StackMapTable. */
1246     StackMapFrame lastFrame = null;
1247 
1248     /** The stack map frame before the last one. */
1249     StackMapFrame frameBeforeLast = null;
1250 
1251     /** Emit a stack map entry.  */
1252     public void emitStackMap() {

1308         }
1309         frame.stack = new Type[state.stacksize];
1310         for (int i=0; i<state.stacksize; i++)
1311             frame.stack[i] = state.stack[i];
1312     }
1313 
1314     void emitStackMapFrame(int pc, int localsSize) {
1315         if (lastFrame == null) {
1316             // first frame
1317             lastFrame = getInitialFrame();
1318         } else if (lastFrame.pc == pc) {
1319             // drop existing stackmap at this offset
1320             stackMapTableBuffer[--stackMapBufferSize] = null;
1321             lastFrame = frameBeforeLast;
1322             frameBeforeLast = null;
1323         }
1324 
1325         StackMapFrame frame = new StackMapFrame();
1326         frame.pc = pc;
1327 

1328         int localCount = 0;
1329         Type[] locals = new Type[localsSize];
1330         for (int i=0; i<localsSize; i++, localCount++) {
1331             if (state.defined.isMember(i) && lvar[i] != null) {
1332                 Type vtype = lvar[i].sym.type;
1333                 if (!(vtype instanceof UninitializedType))
1334                     vtype = types.erasure(vtype);



1335                 locals[i] = vtype;
1336                 if (width(vtype) > 1) i++;
1337             }
1338         }
1339         frame.locals = new Type[localCount];
1340         for (int i=0, j=0; i<localsSize; i++, j++) {
1341             Assert.check(j < localCount);
1342             frame.locals[j] = locals[i];
1343             if (width(locals[i]) > 1) i++;
1344         }
1345 
1346         int stackCount = 0;
1347         for (int i=0; i<state.stacksize; i++) {
1348             if (state.stack[i] != null) {
1349                 stackCount++;
1350             }
1351         }
1352         frame.stack = new Type[stackCount];
1353         stackCount = 0;
1354         for (int i=0; i<state.stacksize; i++) {
1355             if (state.stack[i] != null) {
1356                 frame.stack[stackCount++] = types.erasure(state.stack[i]);
1357             }
1358         }
1359 




1360         if (stackMapTableBuffer == null) {
1361             stackMapTableBuffer = new StackMapTableFrame[20];
1362         } else {
1363             stackMapTableBuffer = ArrayUtils.ensureCapacity(
1364                                     stackMapTableBuffer,
1365                                     stackMapBufferSize);
1366         }
1367         stackMapTableBuffer[stackMapBufferSize++] =
1368                 StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types);







1369 
1370         frameBeforeLast = lastFrame;
1371         lastFrame = frame;
1372     }
1373 




1374     StackMapFrame getInitialFrame() {
1375         StackMapFrame frame = new StackMapFrame();
1376         List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
1377         int len = arg_types.length();
1378         int count = 0;
1379         if (!meth.isStatic()) {
1380             Type thisType = meth.owner.type;
1381             frame.locals = new Type[len+1];
1382             if (meth.isConstructor() && thisType != syms.objectType) {
1383                 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
1384             } else {
1385                 frame.locals[count++] = types.erasure(thisType);
1386             }
1387         } else {
1388             frame.locals = new Type[len];
1389         }
1390         for (Type arg_type : arg_types) {
1391             frame.locals[count++] = types.erasure(arg_type);
1392         }
1393         frame.pc = -1;
1394         frame.stack = null;

1395         return frame;
1396     }
1397 
1398 
1399 /* ************************************************************************
1400  * Operations having to do with jumps
1401  *************************************************************************/
1402 
1403     /** A chain represents a list of unresolved jumps. Jump locations
1404      *  are sorted in decreasing order.
1405      */
1406     public static class Chain {
1407 
1408         /** The position of the jump instruction.
1409          */
1410         public final int pc;
1411 
1412         /** The machine state after the jump instruction.
1413          *  Invariant: all elements of a chain list have the same stacksize
1414          *  and compatible stack and register contents.

1453             return cp - 5;
1454         } else {
1455             emitop2(opcode, 0);
1456             return cp - 3;
1457         }
1458     }
1459 
1460     /** Emit a branch with given opcode; return its chain.
1461      *  branch differs from jump in that jsr is treated as no-op.
1462      */
1463     public Chain branch(int opcode) {
1464         Chain result = null;
1465         if (opcode == goto_) {
1466             result = pendingJumps;
1467             pendingJumps = null;
1468         }
1469         if (opcode != dontgoto && isAlive()) {
1470             result = new Chain(emitJump(opcode),
1471                                result,
1472                                state.dup());



1473             fixedPc = fatcode;
1474             if (opcode == goto_) alive = false;
1475         }
1476         return result;
1477     }
1478 
1479     /** Resolve chain to point to given target.
1480      */
1481     public void resolve(Chain chain, int target) {
1482         boolean changed = false;
1483         State newState = state;

1484         for (; chain != null; chain = chain.next) {
1485             Assert.check(state != chain.state
1486                     && (target > chain.pc || isStatementStart()));
1487             if (target >= cp) {
1488                 target = cp;
1489             } else if (get1(target) == goto_) {
1490                 if (fatcode) target = target + get4(target + 1);
1491                 else target = target + get2(target + 1);
1492             }
1493             if (get1(chain.pc) == goto_ &&
1494                 chain.pc + 3 == target && target == cp && !fixedPc) {
1495                 // If goto the next instruction, the jump is not needed:
1496                 // compact the code.
1497                 if (varDebugInfo) {
1498                     adjustAliveRanges(cp, -3);
1499                 }
1500                 cp = cp - 3;
1501                 target = target - 3;
1502                 if (chain.next == null) {
1503                     // This is the only jump to the target. Exit the loop
1504                     // without setting new state. The code is reachable
1505                     // from the instruction before goto_.
1506                     alive = true;
1507                     break;
1508                 }
1509             } else {
1510                 if (fatcode)
1511                     put4(chain.pc + 1, target - chain.pc);




1512                 else if (target - chain.pc < Short.MIN_VALUE ||
1513                          target - chain.pc > Short.MAX_VALUE)
1514                     fatcode = true;
1515                 else
1516                     put2(chain.pc + 1, target - chain.pc);




1517                 Assert.check(!alive ||
1518                     chain.state.stacksize == newState.stacksize &&
1519                     chain.state.nlocks == newState.nlocks);
1520             }
1521             fixedPc = true;
1522             if (cp == target) {
1523                 changed = true;
1524                 if (debugCode)
1525                     System.err.println("resolving chain state=" + chain.state);
1526                 if (alive) {
1527                     newState = chain.state.join(newState);
1528                 } else {
1529                     newState = chain.state;
1530                     alive = true;
1531                 }
1532             }
1533         }
1534         Assert.check(!changed || state != newState);
1535         if (state != newState) {
1536             setDefined(newState.defined);

  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import com.sun.tools.javac.code.*;
  29 import com.sun.tools.javac.code.Symbol.*;
  30 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  31 import com.sun.tools.javac.util.*;
  32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  33 
  34 import java.util.function.ToIntBiFunction;

  35 
  36 import static com.sun.tools.javac.code.TypeTag.ARRAY;
  37 import static com.sun.tools.javac.code.TypeTag.BOT;
  38 import static com.sun.tools.javac.code.TypeTag.DOUBLE;
  39 import static com.sun.tools.javac.code.TypeTag.INT;
  40 import static com.sun.tools.javac.code.TypeTag.LONG;
  41 import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
  42 import static com.sun.tools.javac.jvm.ByteCodes.*;











  43 import static com.sun.tools.javac.jvm.UninitializedType.*;
  44 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
  45 import java.util.Arrays;
  46 import java.util.Map;
  47 import java.util.HashMap;
  48 import java.util.Set;
  49 
  50 /** An internal structure that corresponds to the code attribute of
  51  *  methods in a classfile. The class also provides some utility operations to
  52  *  generate bytecode instructions.
  53  *
  54  *  <p><b>This is NOT part of any supported API.
  55  *  If you write code that depends on this, you do so at your own risk.
  56  *  This code and its internal interfaces are subject to change or
  57  *  deletion without notice.</b>
  58  */
  59 public class Code {
  60 
  61     public final boolean debugCode;
  62     public final boolean needStackMap;
  63 
  64     public enum StackMapFormat {
  65         NONE,
  66         CLDC {
  67             Name getAttributeName(Names names) {
  68                 return names.StackMap;

 173 
 174     /** The stack map format to be generated. */
 175     StackMapFormat stackMap;
 176 
 177     /** Switch: emit variable debug info.
 178      */
 179     boolean varDebugInfo;
 180 
 181     /** Switch: emit line number info.
 182      */
 183     boolean lineDebugInfo;
 184 
 185     /** Emit line number info if map supplied
 186      */
 187     Position.LineMap lineMap;
 188 
 189     final MethodSymbol meth;
 190 
 191     private int letExprStackPos = 0;
 192 
 193     private Map<Integer, Set<VarSymbol>> cpToUnsetFieldsMap = new HashMap<>();
 194 
 195     public Set<VarSymbol> initialUnsetFields;
 196 
 197     public Set<VarSymbol> currentUnsetFields;
 198 
 199     boolean generateEarlyLarvalFrame;
 200 
 201     /** Construct a code object, given the settings of the fatcode,
 202      *  debugging info switches and the CharacterRangeTable.
 203      */
 204     public Code(MethodSymbol meth,
 205                 boolean fatcode,
 206                 Position.LineMap lineMap,
 207                 boolean varDebugInfo,
 208                 StackMapFormat stackMap,
 209                 boolean debugCode,
 210                 CRTable crt,
 211                 Symtab syms,
 212                 Types types,
 213                 PoolWriter poolWriter,
 214                 boolean generateEarlyLarvalFrame) {
 215         this.meth = meth;
 216         this.fatcode = fatcode;
 217         this.lineMap = lineMap;
 218         this.lineDebugInfo = lineMap != null;
 219         this.varDebugInfo = varDebugInfo;
 220         this.crt = crt;
 221         this.syms = syms;
 222         this.types = types;
 223         this.poolWriter = poolWriter;
 224         this.debugCode = debugCode;
 225         this.stackMap = stackMap;
 226         switch (stackMap) {
 227         case CLDC:
 228         case JSR202:
 229             this.needStackMap = true;
 230             break;
 231         default:
 232             this.needStackMap = false;
 233         }
 234         state = new State();
 235         lvar = new LocalVar[20];
 236         this.generateEarlyLarvalFrame = generateEarlyLarvalFrame;
 237     }
 238 
 239 
 240 /* **************************************************************************
 241  * Typecodes & related stuff
 242  ****************************************************************************/
 243 
 244     /** Given a type, return its type code (used implicitly in the
 245      *  JVM architecture).
 246      */
 247     public static int typecode(Type type) {
 248         switch (type.getTag()) {
 249         case BYTE: return BYTEcode;
 250         case SHORT: return SHORTcode;
 251         case CHAR: return CHARcode;
 252         case INT: return INTcode;
 253         case LONG: return LONGcode;
 254         case FLOAT: return FLOATcode;
 255         case DOUBLE: return DOUBLEcode;
 256         case BOOLEAN: return BYTEcode;

1067         case checkcast: {
1068             state.pop(1); // object ref
1069             Type t = types.erasure((Type)data);
1070             state.push(t);
1071             break; }
1072         case ldc2:
1073         case ldc2w:
1074             state.push(types.constantType((LoadableConstant)data));
1075             break;
1076         case instanceof_:
1077             state.pop(1);
1078             state.push(syms.intType);
1079             break;
1080         case jsr:
1081             break;
1082         default:
1083             throw new AssertionError(mnem(op));
1084         }
1085         // postop();
1086     }

1087     /** Emit an opcode with a four-byte operand field.
1088      */
1089     public void emitop4(int op, int od) {
1090         emitop(op);
1091         if (!alive) return;
1092         emit4(od);
1093         switch (op) {
1094         case goto_w:
1095             markDead();
1096             break;
1097         case jsr_w:
1098             break;
1099         default:
1100             throw new AssertionError(mnem(op));
1101         }
1102         // postop();
1103     }
1104 
1105     /** Align code pointer to next `incr' boundary.
1106      */

1213 
1214     public int setLetExprStackPos(int pos) {
1215         int res = letExprStackPos;
1216         letExprStackPos = pos;
1217         return res;
1218     }
1219 
1220     public boolean isStatementStart() {
1221         return !alive || state.stacksize == letExprStackPos;
1222     }
1223 
1224 /* ************************************************************************
1225  * Stack map generation
1226  *************************************************************************/
1227 
1228     /** An entry in the stack map. */
1229     static class StackMapFrame {
1230         int pc;
1231         Type[] locals;
1232         Type[] stack;
1233         Set<VarSymbol> unsetFields;
1234     }
1235 
1236     /** A buffer of cldc stack map entries. */
1237     StackMapFrame[] stackMapBuffer = null;
1238 
1239     /** A buffer of compressed StackMapTable entries. */
1240     StackMapTableFrame[] stackMapTableBuffer = null;
1241     int stackMapBufferSize = 0;
1242 
1243     /** The last PC at which we generated a stack map. */
1244     int lastStackMapPC = -1;
1245 
1246     /** The last stack map frame in StackMapTable. */
1247     StackMapFrame lastFrame = null;
1248 
1249     /** The stack map frame before the last one. */
1250     StackMapFrame frameBeforeLast = null;
1251 
1252     /** Emit a stack map entry.  */
1253     public void emitStackMap() {

1309         }
1310         frame.stack = new Type[state.stacksize];
1311         for (int i=0; i<state.stacksize; i++)
1312             frame.stack[i] = state.stack[i];
1313     }
1314 
1315     void emitStackMapFrame(int pc, int localsSize) {
1316         if (lastFrame == null) {
1317             // first frame
1318             lastFrame = getInitialFrame();
1319         } else if (lastFrame.pc == pc) {
1320             // drop existing stackmap at this offset
1321             stackMapTableBuffer[--stackMapBufferSize] = null;
1322             lastFrame = frameBeforeLast;
1323             frameBeforeLast = null;
1324         }
1325 
1326         StackMapFrame frame = new StackMapFrame();
1327         frame.pc = pc;
1328 
1329         boolean hasUninitalizedThis = false;
1330         int localCount = 0;
1331         Type[] locals = new Type[localsSize];
1332         for (int i=0; i<localsSize; i++, localCount++) {
1333             if (state.defined.isMember(i) && lvar[i] != null) {
1334                 Type vtype = lvar[i].sym.type;
1335                 if (!(vtype instanceof UninitializedType)) {
1336                     vtype = types.erasure(vtype);
1337                 } else if (vtype.hasTag(TypeTag.UNINITIALIZED_THIS)) {
1338                     hasUninitalizedThis = true;
1339                 }
1340                 locals[i] = vtype;
1341                 if (width(vtype) > 1) i++;
1342             }
1343         }
1344         frame.locals = new Type[localCount];
1345         for (int i=0, j=0; i<localsSize; i++, j++) {
1346             Assert.check(j < localCount);
1347             frame.locals[j] = locals[i];
1348             if (width(locals[i]) > 1) i++;
1349         }
1350 
1351         int stackCount = 0;
1352         for (int i=0; i<state.stacksize; i++) {
1353             if (state.stack[i] != null) {
1354                 stackCount++;
1355             }
1356         }
1357         frame.stack = new Type[stackCount];
1358         stackCount = 0;
1359         for (int i=0; i<state.stacksize; i++) {
1360             if (state.stack[i] != null) {
1361                 frame.stack[stackCount++] = types.erasure(state.stack[i]);
1362             }
1363         }
1364 
1365         Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc);
1366         boolean encloseWithEarlyLarvalFrame = unsetFieldsAtPC != null && generateEarlyLarvalFrame && hasUninitalizedThis
1367                 && !lastFrame.unsetFields.equals(unsetFieldsAtPC);
1368 
1369         if (stackMapTableBuffer == null) {
1370             stackMapTableBuffer = new StackMapTableFrame[20];
1371         } else {
1372             stackMapTableBuffer = ArrayUtils.ensureCapacity(
1373                                     stackMapTableBuffer,
1374                                     stackMapBufferSize);
1375         }
1376 
1377         StackMapTableFrame tableFrame = StackMapTableFrame.getInstance(frame, lastFrame, types, pc);
1378         if (encloseWithEarlyLarvalFrame) {
1379             tableFrame = new StackMapTableFrame.EarlyLarvalFrame(tableFrame, unsetFieldsAtPC);
1380             frame.unsetFields = unsetFieldsAtPC;
1381         } else {
1382             frame.unsetFields = lastFrame.unsetFields;
1383         }
1384         stackMapTableBuffer[stackMapBufferSize++] = tableFrame;
1385 
1386         frameBeforeLast = lastFrame;
1387         lastFrame = frame;
1388     }
1389 
1390     public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) {
1391         cpToUnsetFieldsMap.put(pc, unsetFields);
1392     }
1393 
1394     StackMapFrame getInitialFrame() {
1395         StackMapFrame frame = new StackMapFrame();
1396         List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
1397         int len = arg_types.length();
1398         int count = 0;
1399         if (!meth.isStatic()) {
1400             Type thisType = meth.owner.type;
1401             frame.locals = new Type[len+1];
1402             if (meth.isConstructor() && thisType != syms.objectType) {
1403                 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
1404             } else {
1405                 frame.locals[count++] = types.erasure(thisType);
1406             }
1407         } else {
1408             frame.locals = new Type[len];
1409         }
1410         for (Type arg_type : arg_types) {
1411             frame.locals[count++] = types.erasure(arg_type);
1412         }
1413         frame.pc = -1;
1414         frame.stack = null;
1415         frame.unsetFields = initialUnsetFields;
1416         return frame;
1417     }
1418 
1419 
1420 /* ************************************************************************
1421  * Operations having to do with jumps
1422  *************************************************************************/
1423 
1424     /** A chain represents a list of unresolved jumps. Jump locations
1425      *  are sorted in decreasing order.
1426      */
1427     public static class Chain {
1428 
1429         /** The position of the jump instruction.
1430          */
1431         public final int pc;
1432 
1433         /** The machine state after the jump instruction.
1434          *  Invariant: all elements of a chain list have the same stacksize
1435          *  and compatible stack and register contents.

1474             return cp - 5;
1475         } else {
1476             emitop2(opcode, 0);
1477             return cp - 3;
1478         }
1479     }
1480 
1481     /** Emit a branch with given opcode; return its chain.
1482      *  branch differs from jump in that jsr is treated as no-op.
1483      */
1484     public Chain branch(int opcode) {
1485         Chain result = null;
1486         if (opcode == goto_) {
1487             result = pendingJumps;
1488             pendingJumps = null;
1489         }
1490         if (opcode != dontgoto && isAlive()) {
1491             result = new Chain(emitJump(opcode),
1492                                result,
1493                                state.dup());
1494             if (currentUnsetFields != null) {
1495                 addUnsetFieldsAtPC(result.pc, currentUnsetFields);
1496             }
1497             fixedPc = fatcode;
1498             if (opcode == goto_) alive = false;
1499         }
1500         return result;
1501     }
1502 
1503     /** Resolve chain to point to given target.
1504      */
1505     public void resolve(Chain chain, int target) {
1506         boolean changed = false;
1507         State newState = state;
1508         int originalTarget = target;
1509         for (; chain != null; chain = chain.next) {
1510             Assert.check(state != chain.state
1511                     && (target > chain.pc || isStatementStart()));
1512             if (target >= cp) {
1513                 target = cp;
1514             } else if (get1(target) == goto_) {
1515                 if (fatcode) target = target + get4(target + 1);
1516                 else target = target + get2(target + 1);
1517             }
1518             if (get1(chain.pc) == goto_ &&
1519                 chain.pc + 3 == target && target == cp && !fixedPc) {
1520                 // If goto the next instruction, the jump is not needed:
1521                 // compact the code.
1522                 if (varDebugInfo) {
1523                     adjustAliveRanges(cp, -3);
1524                 }
1525                 cp = cp - 3;
1526                 target = target - 3;
1527                 if (chain.next == null) {
1528                     // This is the only jump to the target. Exit the loop
1529                     // without setting new state. The code is reachable
1530                     // from the instruction before goto_.
1531                     alive = true;
1532                     break;
1533                 }
1534             } else {
1535                 if (fatcode) {
1536                     put4(chain.pc + 1, target - chain.pc);
1537                     if (cpToUnsetFieldsMap.get(chain.pc) != null) {
1538                         addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
1539                     }
1540                 }
1541                 else if (target - chain.pc < Short.MIN_VALUE ||
1542                          target - chain.pc > Short.MAX_VALUE)
1543                     fatcode = true;
1544                 else {
1545                     put2(chain.pc + 1, target - chain.pc);
1546                     if (cpToUnsetFieldsMap.get(chain.pc) != null) {
1547                         addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
1548                     }
1549                 }
1550                 Assert.check(!alive ||
1551                     chain.state.stacksize == newState.stacksize &&
1552                     chain.state.nlocks == newState.nlocks);
1553             }
1554             fixedPc = true;
1555             if (cp == target) {
1556                 changed = true;
1557                 if (debugCode)
1558                     System.err.println("resolving chain state=" + chain.state);
1559                 if (alive) {
1560                     newState = chain.state.join(newState);
1561                 } else {
1562                     newState = chain.state;
1563                     alive = true;
1564                 }
1565             }
1566         }
1567         Assert.check(!changed || state != newState);
1568         if (state != newState) {
1569             setDefined(newState.defined);
< prev index next >