< prev index next >

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

Print this page

   1 /*
   2  * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  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.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.jvm.ByteCodes.*;
  42 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
  43 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
  44 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
  45 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
  46 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
  47 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
  48 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
  49 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
  50 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
  51 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
  52 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
  53 import static com.sun.tools.javac.jvm.UninitializedType.*;
  54 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
  55 import java.util.Arrays;



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

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








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

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

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

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

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

1231     }
1232 
1233     /** A buffer of cldc stack map entries. */
1234     StackMapFrame[] stackMapBuffer = null;
1235 
1236     /** A buffer of compressed StackMapTable entries. */
1237     StackMapTableFrame[] stackMapTableBuffer = null;
1238     int stackMapBufferSize = 0;
1239 
1240     /** The last PC at which we generated a stack map. */
1241     int lastStackMapPC = -1;
1242 
1243     /** The last stack map frame in StackMapTable. */
1244     StackMapFrame lastFrame = null;
1245 
1246     /** The stack map frame before the last one. */
1247     StackMapFrame frameBeforeLast = null;
1248 
1249     /** Emit a stack map entry.  */
1250     public void emitStackMap() {
1251         int pc = curCP();
1252         if (!needStackMap) return;
1253 
1254 
1255 
1256         switch (stackMap) {
1257             case CLDC:

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



1358         if (stackMapTableBuffer == null) {
1359             stackMapTableBuffer = new StackMapTableFrame[20];
1360         } else {
1361             stackMapTableBuffer = ArrayUtils.ensureCapacity(
1362                                     stackMapTableBuffer,
1363                                     stackMapBufferSize);







1364         }
1365         stackMapTableBuffer[stackMapBufferSize++] =
1366                 StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types);
1367 
1368         frameBeforeLast = lastFrame;
1369         lastFrame = frame;
1370     }
1371 




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

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

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



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

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




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




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

   1 /*
   2  * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  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.BOT;
  37 import static com.sun.tools.javac.code.TypeTag.DOUBLE;
  38 import static com.sun.tools.javac.code.TypeTag.INT;
  39 import static com.sun.tools.javac.code.TypeTag.LONG;
  40 import static com.sun.tools.javac.jvm.ByteCodes.*;











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

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

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

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

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

1339         for (int i=0, j=0; i<localsSize; i++, j++) {
1340             Assert.check(j < localCount);
1341             frame.locals[j] = locals[i];
1342             if (width(locals[i]) > 1) i++;
1343         }
1344 
1345         int stackCount = 0;
1346         for (int i=0; i<state.stacksize; i++) {
1347             if (state.stack[i] != null) {
1348                 stackCount++;
1349             }
1350         }
1351         frame.stack = new Type[stackCount];
1352         stackCount = 0;
1353         for (int i=0; i<state.stacksize; i++) {
1354             if (state.stack[i] != null) {
1355                 frame.stack[stackCount++] = types.erasure(state.stack[i]);
1356             }
1357         }
1358 
1359         Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc);
1360         boolean generateAssertUnsetFieldsEntry = unsetFieldsAtPC != null && generateAssertUnsetFieldsFrame && !lastFrame.unsetFields.equals(unsetFieldsAtPC) ;
1361 
1362         if (stackMapTableBuffer == null) {
1363             stackMapTableBuffer = new StackMapTableEntry[20];
1364         } else {
1365             stackMapTableBuffer = ArrayUtils.ensureCapacity(
1366                                     stackMapTableBuffer,
1367                                     stackMapBufferSize + (generateAssertUnsetFieldsEntry ? 1 : 0));
1368         }
1369 
1370         if (generateAssertUnsetFieldsEntry) {
1371             stackMapTableBuffer[stackMapBufferSize++] = new StackMapTableEntry.AssertUnsetFields(pc, unsetFieldsAtPC);
1372             frame.unsetFields = unsetFieldsAtPC;
1373         } else {
1374             frame.unsetFields = lastFrame.unsetFields;
1375         }
1376         stackMapTableBuffer[stackMapBufferSize++] =
1377                 StackMapTableEntry.getInstance(frame, lastFrame, types, pc);
1378 
1379         frameBeforeLast = lastFrame;
1380         lastFrame = frame;
1381     }
1382 
1383     public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) {
1384         cpToUnsetFieldsMap.put(pc, unsetFields);
1385     }
1386 
1387     StackMapFrame getInitialFrame() {
1388         StackMapFrame frame = new StackMapFrame();
1389         List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
1390         int len = arg_types.length();
1391         int count = 0;
1392         if (!meth.isStatic()) {
1393             Type thisType = meth.owner.type;
1394             frame.locals = new Type[len+1];
1395             if (meth.isConstructor() && thisType != syms.objectType) {
1396                 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
1397             } else {
1398                 frame.locals[count++] = types.erasure(thisType);
1399             }
1400         } else {
1401             frame.locals = new Type[len];
1402         }
1403         for (Type arg_type : arg_types) {
1404             frame.locals[count++] = types.erasure(arg_type);
1405         }
1406         frame.pc = -1;
1407         frame.stack = null;
1408         frame.unsetFields = initialUnsetFields;
1409         return frame;
1410     }
1411 
1412 
1413 /* ************************************************************************
1414  * Operations having to do with jumps
1415  *************************************************************************/
1416 
1417     /** A chain represents a list of unresolved jumps. Jump locations
1418      *  are sorted in decreasing order.
1419      */
1420     public static class Chain {
1421 
1422         /** The position of the jump instruction.
1423          */
1424         public final int pc;
1425 
1426         /** The machine state after the jump instruction.
1427          *  Invariant: all elements of a chain list have the same stacksize
1428          *  and compatible stack and register contents.

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