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() {
1306 }
1307 frame.stack = new Type[state.stacksize];
1308 for (int i=0; i<state.stacksize; i++)
1309 frame.stack[i] = state.stack[i];
1310 }
1311
1312 void emitStackMapFrame(int pc, int localsSize) {
1313 if (lastFrame == null) {
1314 // first frame
1315 lastFrame = getInitialFrame();
1316 } else if (lastFrame.pc == pc) {
1317 // drop existing stackmap at this offset
1318 stackMapTableBuffer[--stackMapBufferSize] = null;
1319 lastFrame = frameBeforeLast;
1320 frameBeforeLast = null;
1321 }
1322
1323 StackMapFrame frame = new StackMapFrame();
1324 frame.pc = pc;
1325
1326 int localCount = 0;
1327 Type[] locals = new Type[localsSize];
1328 for (int i=0; i<localsSize; i++, localCount++) {
1329 if (state.defined.isMember(i) && lvar[i] != null) {
1330 Type vtype = lvar[i].sym.type;
1331 if (!(vtype instanceof UninitializedType))
1332 vtype = types.erasure(vtype);
1333 locals[i] = vtype;
1334 if (width(vtype) > 1) i++;
1335 }
1336 }
1337 frame.locals = new Type[localCount];
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.StackMapTableFrame;
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 generateEarlyLarvalFrame;
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 generateEarlyLarvalFrame) {
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.generateEarlyLarvalFrame = generateEarlyLarvalFrame;
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 StackMapTableFrame[] 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() {
1307 }
1308 frame.stack = new Type[state.stacksize];
1309 for (int i=0; i<state.stacksize; i++)
1310 frame.stack[i] = state.stack[i];
1311 }
1312
1313 void emitStackMapFrame(int pc, int localsSize) {
1314 if (lastFrame == null) {
1315 // first frame
1316 lastFrame = getInitialFrame();
1317 } else if (lastFrame.pc == pc) {
1318 // drop existing stackmap at this offset
1319 stackMapTableBuffer[--stackMapBufferSize] = null;
1320 lastFrame = frameBeforeLast;
1321 frameBeforeLast = null;
1322 }
1323
1324 StackMapFrame frame = new StackMapFrame();
1325 frame.pc = pc;
1326
1327 boolean hasUninitalizedThis = false;
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 } else if (vtype.hasTag(TypeTag.UNINITIALIZED_THIS)) {
1336 hasUninitalizedThis = true;
1337 }
1338 locals[i] = vtype;
1339 if (width(vtype) > 1) i++;
1340 }
1341 }
1342 frame.locals = new Type[localCount];
1343 for (int i=0, j=0; i<localsSize; i++, j++) {
1344 Assert.check(j < localCount);
1345 frame.locals[j] = locals[i];
1346 if (width(locals[i]) > 1) i++;
1347 }
1348
1349 int stackCount = 0;
1350 for (int i=0; i<state.stacksize; i++) {
1351 if (state.stack[i] != null) {
1352 stackCount++;
1353 }
1354 }
1355 frame.stack = new Type[stackCount];
1356 stackCount = 0;
1357 for (int i=0; i<state.stacksize; i++) {
1358 if (state.stack[i] != null) {
1359 frame.stack[stackCount++] = types.erasure(state.stack[i]);
1360 }
1361 }
1362
1363 Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc);
1364 boolean encloseWithEarlyLarvalFrame = unsetFieldsAtPC != null && generateEarlyLarvalFrame && hasUninitalizedThis
1365 && !lastFrame.unsetFields.equals(unsetFieldsAtPC);
1366
1367 if (stackMapTableBuffer == null) {
1368 stackMapTableBuffer = new StackMapTableFrame[20];
1369 } else {
1370 stackMapTableBuffer = ArrayUtils.ensureCapacity(
1371 stackMapTableBuffer,
1372 stackMapBufferSize);
1373 }
1374
1375 StackMapTableFrame tableFrame = StackMapTableFrame.getInstance(frame, lastFrame, types, pc);
1376 if (encloseWithEarlyLarvalFrame) {
1377 tableFrame = new StackMapTableFrame.EarlyLarvalFrame(tableFrame, unsetFieldsAtPC);
1378 frame.unsetFields = unsetFieldsAtPC;
1379 } else {
1380 frame.unsetFields = lastFrame.unsetFields;
1381 }
1382 stackMapTableBuffer[stackMapBufferSize++] = tableFrame;
1383
1384 frameBeforeLast = lastFrame;
1385 lastFrame = frame;
1386 }
1387
1388 public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) {
1389 cpToUnsetFieldsMap.put(pc, unsetFields);
1390 }
1391
1392 StackMapFrame getInitialFrame() {
1393 StackMapFrame frame = new StackMapFrame();
1394 List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
1395 int len = arg_types.length();
1396 int count = 0;
1397 if (!meth.isStatic()) {
1398 Type thisType = meth.owner.type;
1399 frame.locals = new Type[len+1];
1400 if (meth.isConstructor() && thisType != syms.objectType) {
1401 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
1402 } else {
1403 frame.locals[count++] = types.erasure(thisType);
1404 }
1405 } else {
1406 frame.locals = new Type[len];
1407 }
1408 for (Type arg_type : arg_types) {
1409 frame.locals[count++] = types.erasure(arg_type);
1410 }
1411 frame.pc = -1;
1412 frame.stack = null;
1413 frame.unsetFields = initialUnsetFields;
1414 return frame;
1415 }
1416
1417
1418 /* ************************************************************************
1419 * Operations having to do with jumps
1420 *************************************************************************/
1421
1422 /** A chain represents a list of unresolved jumps. Jump locations
1423 * are sorted in decreasing order.
1424 */
1425 public static class Chain {
1426
1427 /** The position of the jump instruction.
1428 */
1429 public final int pc;
1430
1431 /** The machine state after the jump instruction.
1432 * Invariant: all elements of a chain list have the same stacksize
1433 * and compatible stack and register contents.
1472 return cp - 5;
1473 } else {
1474 emitop2(opcode, 0);
1475 return cp - 3;
1476 }
1477 }
1478
1479 /** Emit a branch with given opcode; return its chain.
1480 * branch differs from jump in that jsr is treated as no-op.
1481 */
1482 public Chain branch(int opcode) {
1483 Chain result = null;
1484 if (opcode == goto_) {
1485 result = pendingJumps;
1486 pendingJumps = null;
1487 }
1488 if (opcode != dontgoto && isAlive()) {
1489 result = new Chain(emitJump(opcode),
1490 result,
1491 state.dup());
1492 if (currentUnsetFields != null) {
1493 addUnsetFieldsAtPC(result.pc, currentUnsetFields);
1494 }
1495 fixedPc = fatcode;
1496 if (opcode == goto_) alive = false;
1497 }
1498 return result;
1499 }
1500
1501 /** Resolve chain to point to given target.
1502 */
1503 public void resolve(Chain chain, int target) {
1504 boolean changed = false;
1505 State newState = state;
1506 int originalTarget = target;
1507 for (; chain != null; chain = chain.next) {
1508 Assert.check(state != chain.state
1509 && (target > chain.pc || isStatementStart()));
1510 if (target >= cp) {
1511 target = cp;
1512 } else if (get1(target) == goto_) {
1513 if (fatcode) target = target + get4(target + 1);
1514 else target = target + get2(target + 1);
1515 }
1516 if (get1(chain.pc) == goto_ &&
1517 chain.pc + 3 == target && target == cp && !fixedPc) {
1518 // If goto the next instruction, the jump is not needed:
1519 // compact the code.
1520 if (varDebugInfo) {
1521 adjustAliveRanges(cp, -3);
1522 }
1523 cp = cp - 3;
1524 target = target - 3;
1525 if (chain.next == null) {
1526 // This is the only jump to the target. Exit the loop
1527 // without setting new state. The code is reachable
1528 // from the instruction before goto_.
1529 alive = true;
1530 break;
1531 }
1532 } else {
1533 if (fatcode) {
1534 put4(chain.pc + 1, target - chain.pc);
1535 if (cpToUnsetFieldsMap.get(chain.pc) != null) {
1536 addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
1537 }
1538 }
1539 else if (target - chain.pc < Short.MIN_VALUE ||
1540 target - chain.pc > Short.MAX_VALUE)
1541 fatcode = true;
1542 else {
1543 put2(chain.pc + 1, target - chain.pc);
1544 if (cpToUnsetFieldsMap.get(chain.pc) != null) {
1545 addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
1546 }
1547 }
1548 Assert.check(!alive ||
1549 chain.state.stacksize == newState.stacksize &&
1550 chain.state.nlocks == newState.nlocks);
1551 }
1552 fixedPc = true;
1553 if (cp == target) {
1554 changed = true;
1555 if (debugCode)
1556 System.err.println("resolving chain state=" + chain.state);
1557 if (alive) {
1558 newState = chain.state.join(newState);
1559 } else {
1560 newState = chain.state;
1561 alive = true;
1562 }
1563 }
1564 }
1565 Assert.check(!changed || state != newState);
1566 if (state != newState) {
1567 setDefined(newState.defined);
|