< 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,

 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;

1039         case iflt:
1040         case ifge:
1041         case ifgt:
1042         case ifle:
1043             state.pop(1);
1044             break;
1045         case if_icmpeq:
1046         case if_icmpne:
1047         case if_icmplt:
1048         case if_icmpge:
1049         case if_icmpgt:
1050         case if_icmple:
1051         case if_acmpeq:
1052         case if_acmpne:
1053             state.pop(2);
1054             break;
1055         case goto_:
1056             markDead();
1057             break;
1058         case putfield:
1059             state.pop(((Symbol)data).erasure(types));






1060             state.pop(1); // object ref
1061             break;
1062         case getfield:
1063             state.pop(1); // object ref
1064             state.push(((Symbol)data).erasure(types));
1065             break;
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.

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);

1640     public void markStatBegin() {
1641         if (alive && lineDebugInfo) {
1642             int line = lineMap.getLineNumber(pendingStatPos);
1643             char cp1 = (char)cp;
1644             char line1 = (char)line;
1645             if (cp1 == cp && line1 == line)
1646                 addLineNumber(cp1, line1);
1647         }
1648         pendingStatPos = Position.NOPOS;
1649     }
1650 
1651 
1652 /* **************************************************************************
1653  * Simulated VM machine state
1654  ****************************************************************************/
1655 
1656     class State implements Cloneable {
1657         /** The set of registers containing values. */
1658         Bits defined;
1659 



1660         /** The (types of the) contents of the machine stack. */
1661         Type[] stack;
1662 
1663         /** The first stack position currently unused. */
1664         int stacksize;
1665 
1666         /** The numbers of registers containing locked monitors. */
1667         int[] locks;
1668         int nlocks;
1669 
1670         State() {
1671             defined = new Bits();

1672             stack = new Type[16];
1673         }
1674 
1675         State dup() {
1676             try {
1677                 State state = (State)super.clone();
1678                 state.defined = new Bits(defined);

1679                 state.stack = stack.clone();
1680                 if (locks != null) state.locks = locks.clone();
1681                 if (debugCode) {
1682                     System.err.println("duping state " + this);
1683                     dump();
1684                 }
1685                 return state;
1686             } catch (CloneNotSupportedException ex) {
1687                 throw new AssertionError(ex);
1688             }
1689         }
1690 
1691         void lock(int register) {
1692             if (locks == null) {
1693                 locks = new int[20];
1694             } else {
1695                 locks = ArrayUtils.ensureCapacity(locks, nlocks);
1696             }
1697             locks[nlocks] = register;
1698             nlocks++;

1787 
1788         void markInitialized(UninitializedType old) {
1789             Type newtype = old.initializedType();
1790             for (int i=0; i<stacksize; i++) {
1791                 if (stack[i] == old) stack[i] = newtype;
1792             }
1793             for (int i=0; i<lvar.length; i++) {
1794                 LocalVar lv = lvar[i];
1795                 if (lv != null && lv.sym.type == old) {
1796                     VarSymbol sym = lv.sym;
1797                     sym = sym.clone(sym.owner);
1798                     sym.type = newtype;
1799                     LocalVar newlv = lvar[i] = new LocalVar(sym);
1800                     newlv.aliveRanges = lv.aliveRanges;
1801                 }
1802             }
1803         }
1804 
1805         State join(State other) {
1806             defined.andSet(other.defined);

1807             Assert.check(stacksize == other.stacksize
1808                     && nlocks == other.nlocks);
1809             for (int i=0; i<stacksize; ) {
1810                 Type t = stack[i];
1811                 Type tother = other.stack[i];
1812                 Type result = commonSuperClass(t, tother);
1813                 int w = width(result);
1814                 stack[i] = result;
1815                 if (w == 2) Assert.checkNull(stack[i+1]);
1816                 i += w;
1817             }
1818             return this;
1819         }
1820 
1821         private Type commonSuperClass(Type t1, Type t2) {
1822             if (t1 == t2) {
1823                 return t1;
1824             } else if (types.isSubtype(t1, t2)) {
1825                 return t2;
1826             } else if (types.isSubtype(t2, t1)) {

  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.UNINITIALIZED_THIS;
  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 
  47 /** An internal structure that corresponds to the code attribute of
  48  *  methods in a classfile. The class also provides some utility operations to
  49  *  generate bytecode instructions.
  50  *
  51  *  <p><b>This is NOT part of any supported API.
  52  *  If you write code that depends on this, you do so at your own risk.
  53  *  This code and its internal interfaces are subject to change or
  54  *  deletion without notice.</b>
  55  */
  56 public class Code {
  57 
  58     public final boolean debugCode;
  59     public final boolean needStackMap;
  60 
  61     public enum StackMapFormat {
  62         NONE,

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

1045         case iflt:
1046         case ifge:
1047         case ifgt:
1048         case ifle:
1049             state.pop(1);
1050             break;
1051         case if_icmpeq:
1052         case if_icmpne:
1053         case if_icmplt:
1054         case if_icmpge:
1055         case if_icmpgt:
1056         case if_icmple:
1057         case if_acmpeq:
1058         case if_acmpne:
1059             state.pop(2);
1060             break;
1061         case goto_:
1062             markDead();
1063             break;
1064         case putfield:
1065             VarSymbol field = (VarSymbol)data;
1066             state.pop(field.erasure(types));
1067             if (field.isStrictInstance() &&
1068                     field.owner == meth.owner &&
1069                     state.peek().hasTag(UNINITIALIZED_THIS)) {
1070                 state.unsetStrict.excl(field.adr);
1071             }
1072             state.pop(1); // object ref
1073             break;
1074         case getfield:
1075             state.pop(1); // object ref
1076             state.push(((Symbol)data).erasure(types));
1077             break;
1078         case checkcast: {
1079             state.pop(1); // object ref
1080             Type t = types.erasure((Type)data);
1081             state.push(t);
1082             break; }
1083         case ldc2:
1084         case ldc2w:
1085             state.push(types.constantType((LoadableConstant)data));
1086             break;
1087         case instanceof_:
1088             state.pop(1);
1089             state.push(syms.intType);
1090             break;
1091         case jsr:
1092             break;
1093         default:
1094             throw new AssertionError(mnem(op));
1095         }
1096         // postop();
1097     }

1098     /** Emit an opcode with a four-byte operand field.
1099      */
1100     public void emitop4(int op, int od) {
1101         emitop(op);
1102         if (!alive) return;
1103         emit4(od);
1104         switch (op) {
1105         case goto_w:
1106             markDead();
1107             break;
1108         case jsr_w:
1109             break;
1110         default:
1111             throw new AssertionError(mnem(op));
1112         }
1113         // postop();
1114     }
1115 
1116     /** Align code pointer to next `incr' boundary.
1117      */

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

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

1498         Chain result = null;
1499         if (opcode == goto_) {
1500             result = pendingJumps;
1501             pendingJumps = null;
1502         }
1503         if (opcode != dontgoto && isAlive()) {
1504             result = new Chain(emitJump(opcode),
1505                                result,
1506                                state.dup());
1507             fixedPc = fatcode;
1508             if (opcode == goto_) alive = false;
1509         }
1510         return result;
1511     }
1512 
1513     /** Resolve chain to point to given target.
1514      */
1515     public void resolve(Chain chain, int target) {
1516         boolean changed = false;
1517         State newState = state;
1518         int originalTarget = target;
1519         for (; chain != null; chain = chain.next) {
1520             Assert.check(state != chain.state
1521                     && (target > chain.pc || isStatementStart()));
1522             if (target >= cp) {
1523                 target = cp;
1524             } else if (get1(target) == goto_) {
1525                 if (fatcode) target = target + get4(target + 1);
1526                 else target = target + get2(target + 1);
1527             }
1528             if (get1(chain.pc) == goto_ &&
1529                 chain.pc + 3 == target && target == cp && !fixedPc) {
1530                 // If goto the next instruction, the jump is not needed:
1531                 // compact the code.
1532                 if (varDebugInfo) {
1533                     adjustAliveRanges(cp, -3);
1534                 }
1535                 cp = cp - 3;
1536                 target = target - 3;
1537                 if (chain.next == null) {
1538                     // This is the only jump to the target. Exit the loop
1539                     // without setting new state. The code is reachable
1540                     // from the instruction before goto_.
1541                     alive = true;
1542                     break;
1543                 }
1544             } else {
1545                 if (fatcode) {
1546                     put4(chain.pc + 1, target - chain.pc);
1547                 }
1548                 else if (target - chain.pc < Short.MIN_VALUE ||
1549                          target - chain.pc > Short.MAX_VALUE)
1550                     fatcode = true;
1551                 else {
1552                     put2(chain.pc + 1, target - chain.pc);
1553                 }
1554                 Assert.check(!alive ||
1555                     chain.state.stacksize == newState.stacksize &&
1556                     chain.state.nlocks == newState.nlocks);
1557             }
1558             fixedPc = true;
1559             if (cp == target) {
1560                 changed = true;
1561                 if (debugCode)
1562                     System.err.println("resolving chain state=" + chain.state);
1563                 if (alive) {
1564                     newState = chain.state.join(newState);
1565                 } else {
1566                     newState = chain.state;
1567                     alive = true;
1568                 }
1569             }
1570         }
1571         Assert.check(!changed || state != newState);
1572         if (state != newState) {
1573             setDefined(newState.defined);

1677     public void markStatBegin() {
1678         if (alive && lineDebugInfo) {
1679             int line = lineMap.getLineNumber(pendingStatPos);
1680             char cp1 = (char)cp;
1681             char line1 = (char)line;
1682             if (cp1 == cp && line1 == line)
1683                 addLineNumber(cp1, line1);
1684         }
1685         pendingStatPos = Position.NOPOS;
1686     }
1687 
1688 
1689 /* **************************************************************************
1690  * Simulated VM machine state
1691  ****************************************************************************/
1692 
1693     class State implements Cloneable {
1694         /** The set of registers containing values. */
1695         Bits defined;
1696 
1697         /** The unset strict fields. */
1698         Bits unsetStrict;
1699 
1700         /** The (types of the) contents of the machine stack. */
1701         Type[] stack;
1702 
1703         /** The first stack position currently unused. */
1704         int stacksize;
1705 
1706         /** The numbers of registers containing locked monitors. */
1707         int[] locks;
1708         int nlocks;
1709 
1710         State() {
1711             defined = new Bits();
1712             unsetStrict = new Bits();
1713             stack = new Type[16];
1714         }
1715 
1716         State dup() {
1717             try {
1718                 State state = (State)super.clone();
1719                 state.defined = new Bits(defined);
1720                 state.unsetStrict = new Bits(unsetStrict);
1721                 state.stack = stack.clone();
1722                 if (locks != null) state.locks = locks.clone();
1723                 if (debugCode) {
1724                     System.err.println("duping state " + this);
1725                     dump();
1726                 }
1727                 return state;
1728             } catch (CloneNotSupportedException ex) {
1729                 throw new AssertionError(ex);
1730             }
1731         }
1732 
1733         void lock(int register) {
1734             if (locks == null) {
1735                 locks = new int[20];
1736             } else {
1737                 locks = ArrayUtils.ensureCapacity(locks, nlocks);
1738             }
1739             locks[nlocks] = register;
1740             nlocks++;

1829 
1830         void markInitialized(UninitializedType old) {
1831             Type newtype = old.initializedType();
1832             for (int i=0; i<stacksize; i++) {
1833                 if (stack[i] == old) stack[i] = newtype;
1834             }
1835             for (int i=0; i<lvar.length; i++) {
1836                 LocalVar lv = lvar[i];
1837                 if (lv != null && lv.sym.type == old) {
1838                     VarSymbol sym = lv.sym;
1839                     sym = sym.clone(sym.owner);
1840                     sym.type = newtype;
1841                     LocalVar newlv = lvar[i] = new LocalVar(sym);
1842                     newlv.aliveRanges = lv.aliveRanges;
1843                 }
1844             }
1845         }
1846 
1847         State join(State other) {
1848             defined.andSet(other.defined);
1849             unsetStrict.orSet(other.unsetStrict);
1850             Assert.check(stacksize == other.stacksize
1851                     && nlocks == other.nlocks);
1852             for (int i=0; i<stacksize; ) {
1853                 Type t = stack[i];
1854                 Type tother = other.stack[i];
1855                 Type result = commonSuperClass(t, tother);
1856                 int w = width(result);
1857                 stack[i] = result;
1858                 if (w == 2) Assert.checkNull(stack[i+1]);
1859                 i += w;
1860             }
1861             return this;
1862         }
1863 
1864         private Type commonSuperClass(Type t1, Type t2) {
1865             if (t1 == t2) {
1866                 return t1;
1867             } else if (types.isSubtype(t1, t2)) {
1868                 return t2;
1869             } else if (types.isSubtype(t2, t1)) {
< prev index next >