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