1 /*
2 * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.jvm;
27
28 import com.sun.tools.javac.code.*;
29 import com.sun.tools.javac.code.Symbol.*;
30 import com.sun.tools.javac.resources.CompilerProperties.Errors;
31 import com.sun.tools.javac.util.*;
32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
33
34 import java.util.function.ToIntBiFunction;
35 import java.util.function.ToIntFunction;
36
37 import static com.sun.tools.javac.code.TypeTag.BOT;
38 import static com.sun.tools.javac.code.TypeTag.DOUBLE;
39 import static com.sun.tools.javac.code.TypeTag.INT;
40 import static com.sun.tools.javac.code.TypeTag.LONG;
41 import static com.sun.tools.javac.jvm.ByteCodes.*;
42 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
43 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
44 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
45 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
46 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
47 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
48 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
49 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
50 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
51 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
52 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
53 import static com.sun.tools.javac.jvm.UninitializedType.*;
54 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
55 import java.util.Arrays;
56
57 /** An internal structure that corresponds to the code attribute of
58 * methods in a classfile. The class also provides some utility operations to
59 * generate bytecode instructions.
60 *
61 * <p><b>This is NOT part of any supported API.
62 * If you write code that depends on this, you do so at your own risk.
63 * This code and its internal interfaces are subject to change or
64 * deletion without notice.</b>
65 */
66 public class Code {
67
68 public final boolean debugCode;
69 public final boolean needStackMap;
70
71 public enum StackMapFormat {
72 NONE,
73 CLDC {
74 Name getAttributeName(Names names) {
75 return names.StackMap;
180
181 /** The stack map format to be generated. */
182 StackMapFormat stackMap;
183
184 /** Switch: emit variable debug info.
185 */
186 boolean varDebugInfo;
187
188 /** Switch: emit line number info.
189 */
190 boolean lineDebugInfo;
191
192 /** Emit line number info if map supplied
193 */
194 Position.LineMap lineMap;
195
196 final MethodSymbol meth;
197
198 private int letExprStackPos = 0;
199
200 /** Construct a code object, given the settings of the fatcode,
201 * debugging info switches and the CharacterRangeTable.
202 */
203 public Code(MethodSymbol meth,
204 boolean fatcode,
205 Position.LineMap lineMap,
206 boolean varDebugInfo,
207 StackMapFormat stackMap,
208 boolean debugCode,
209 CRTable crt,
210 Symtab syms,
211 Types types,
212 PoolWriter poolWriter) {
213 this.meth = meth;
214 this.fatcode = fatcode;
215 this.lineMap = lineMap;
216 this.lineDebugInfo = lineMap != null;
217 this.varDebugInfo = varDebugInfo;
218 this.crt = crt;
219 this.syms = syms;
220 this.types = types;
221 this.poolWriter = poolWriter;
222 this.debugCode = debugCode;
223 this.stackMap = stackMap;
224 switch (stackMap) {
225 case CLDC:
226 case JSR202:
227 this.needStackMap = true;
228 break;
229 default:
230 this.needStackMap = false;
231 }
232 state = new State();
233 lvar = new LocalVar[20];
234 }
235
236
237 /* **************************************************************************
238 * Typecodes & related stuff
239 ****************************************************************************/
240
241 /** Given a type, return its type code (used implicitly in the
242 * JVM architecture).
243 */
244 public static int typecode(Type type) {
245 switch (type.getTag()) {
246 case BYTE: return BYTEcode;
247 case SHORT: return SHORTcode;
248 case CHAR: return CHARcode;
249 case INT: return INTcode;
250 case LONG: return LONGcode;
251 case FLOAT: return FLOATcode;
252 case DOUBLE: return DOUBLEcode;
253 case BOOLEAN: return BYTEcode;
1064 case checkcast: {
1065 state.pop(1); // object ref
1066 Type t = types.erasure((Type)data);
1067 state.push(t);
1068 break; }
1069 case ldc2:
1070 case ldc2w:
1071 state.push(types.constantType((LoadableConstant)data));
1072 break;
1073 case instanceof_:
1074 state.pop(1);
1075 state.push(syms.intType);
1076 break;
1077 case jsr:
1078 break;
1079 default:
1080 throw new AssertionError(mnem(op));
1081 }
1082 // postop();
1083 }
1084
1085 /** Emit an opcode with a four-byte operand field.
1086 */
1087 public void emitop4(int op, int od) {
1088 emitop(op);
1089 if (!alive) return;
1090 emit4(od);
1091 switch (op) {
1092 case goto_w:
1093 markDead();
1094 break;
1095 case jsr_w:
1096 break;
1097 default:
1098 throw new AssertionError(mnem(op));
1099 }
1100 // postop();
1101 }
1102
1103 /** Align code pointer to next `incr' boundary.
1104 */
1211
1212 public int setLetExprStackPos(int pos) {
1213 int res = letExprStackPos;
1214 letExprStackPos = pos;
1215 return res;
1216 }
1217
1218 public boolean isStatementStart() {
1219 return !alive || state.stacksize == letExprStackPos;
1220 }
1221
1222 /* ************************************************************************
1223 * Stack map generation
1224 *************************************************************************/
1225
1226 /** An entry in the stack map. */
1227 static class StackMapFrame {
1228 int pc;
1229 Type[] locals;
1230 Type[] stack;
1231 }
1232
1233 /** A buffer of cldc stack map entries. */
1234 StackMapFrame[] stackMapBuffer = null;
1235
1236 /** A buffer of compressed StackMapTable entries. */
1237 StackMapTableFrame[] stackMapTableBuffer = null;
1238 int stackMapBufferSize = 0;
1239
1240 /** The last PC at which we generated a stack map. */
1241 int lastStackMapPC = -1;
1242
1243 /** The last stack map frame in StackMapTable. */
1244 StackMapFrame lastFrame = null;
1245
1246 /** The stack map frame before the last one. */
1247 StackMapFrame frameBeforeLast = null;
1248
1249 /** Emit a stack map entry. */
1250 public void emitStackMap() {
1251 int pc = curCP();
1252 if (!needStackMap) return;
1253
1254
1255
1256 switch (stackMap) {
1257 case CLDC:
1338 for (int i=0, j=0; i<localsSize; i++, j++) {
1339 Assert.check(j < localCount);
1340 frame.locals[j] = locals[i];
1341 if (width(locals[i]) > 1) i++;
1342 }
1343
1344 int stackCount = 0;
1345 for (int i=0; i<state.stacksize; i++) {
1346 if (state.stack[i] != null) {
1347 stackCount++;
1348 }
1349 }
1350 frame.stack = new Type[stackCount];
1351 stackCount = 0;
1352 for (int i=0; i<state.stacksize; i++) {
1353 if (state.stack[i] != null) {
1354 frame.stack[stackCount++] = types.erasure(state.stack[i]);
1355 }
1356 }
1357
1358 if (stackMapTableBuffer == null) {
1359 stackMapTableBuffer = new StackMapTableFrame[20];
1360 } else {
1361 stackMapTableBuffer = ArrayUtils.ensureCapacity(
1362 stackMapTableBuffer,
1363 stackMapBufferSize);
1364 }
1365 stackMapTableBuffer[stackMapBufferSize++] =
1366 StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types);
1367
1368 frameBeforeLast = lastFrame;
1369 lastFrame = frame;
1370 }
1371
1372 StackMapFrame getInitialFrame() {
1373 StackMapFrame frame = new StackMapFrame();
1374 List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
1375 int len = arg_types.length();
1376 int count = 0;
1377 if (!meth.isStatic()) {
1378 Type thisType = meth.owner.type;
1379 frame.locals = new Type[len+1];
1380 if (meth.isConstructor() && thisType != syms.objectType) {
1381 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
1382 } else {
1383 frame.locals[count++] = types.erasure(thisType);
1384 }
1385 } else {
1386 frame.locals = new Type[len];
1387 }
1388 for (Type arg_type : arg_types) {
1389 frame.locals[count++] = types.erasure(arg_type);
1390 }
1391 frame.pc = -1;
1451 return cp - 5;
1452 } else {
1453 emitop2(opcode, 0);
1454 return cp - 3;
1455 }
1456 }
1457
1458 /** Emit a branch with given opcode; return its chain.
1459 * branch differs from jump in that jsr is treated as no-op.
1460 */
1461 public Chain branch(int opcode) {
1462 Chain result = null;
1463 if (opcode == goto_) {
1464 result = pendingJumps;
1465 pendingJumps = null;
1466 }
1467 if (opcode != dontgoto && isAlive()) {
1468 result = new Chain(emitJump(opcode),
1469 result,
1470 state.dup());
1471 fixedPc = fatcode;
1472 if (opcode == goto_) alive = false;
1473 }
1474 return result;
1475 }
1476
1477 /** Resolve chain to point to given target.
1478 */
1479 public void resolve(Chain chain, int target) {
1480 boolean changed = false;
1481 State newState = state;
1482 for (; chain != null; chain = chain.next) {
1483 Assert.check(state != chain.state
1484 && (target > chain.pc || isStatementStart()));
1485 if (target >= cp) {
1486 target = cp;
1487 } else if (get1(target) == goto_) {
1488 if (fatcode) target = target + get4(target + 1);
1489 else target = target + get2(target + 1);
1490 }
1491 if (get1(chain.pc) == goto_ &&
1492 chain.pc + 3 == target && target == cp && !fixedPc) {
1493 // If goto the next instruction, the jump is not needed:
1494 // compact the code.
1495 if (varDebugInfo) {
1496 adjustAliveRanges(cp, -3);
1497 }
1498 cp = cp - 3;
1499 target = target - 3;
1500 if (chain.next == null) {
1501 // This is the only jump to the target. Exit the loop
1502 // without setting new state. The code is reachable
1503 // from the instruction before goto_.
1504 alive = true;
1505 break;
1506 }
1507 } else {
1508 if (fatcode)
1509 put4(chain.pc + 1, target - chain.pc);
1510 else if (target - chain.pc < Short.MIN_VALUE ||
1511 target - chain.pc > Short.MAX_VALUE)
1512 fatcode = true;
1513 else
1514 put2(chain.pc + 1, target - chain.pc);
1515 Assert.check(!alive ||
1516 chain.state.stacksize == newState.stacksize &&
1517 chain.state.nlocks == newState.nlocks);
1518 }
1519 fixedPc = true;
1520 if (cp == target) {
1521 changed = true;
1522 if (debugCode)
1523 System.err.println("resolving chain state=" + chain.state);
1524 if (alive) {
1525 newState = chain.state.join(newState);
1526 } else {
1527 newState = chain.state;
1528 alive = true;
1529 }
1530 }
1531 }
1532 Assert.check(!changed || state != newState);
1533 if (state != newState) {
1534 setDefined(newState.defined);
|
1 /*
2 * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.jvm;
27
28 import com.sun.tools.javac.code.*;
29 import com.sun.tools.javac.code.Symbol.*;
30 import com.sun.tools.javac.resources.CompilerProperties.Errors;
31 import com.sun.tools.javac.util.*;
32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
33
34 import java.util.function.ToIntBiFunction;
35
36 import static com.sun.tools.javac.code.TypeTag.BOT;
37 import static com.sun.tools.javac.code.TypeTag.DOUBLE;
38 import static com.sun.tools.javac.code.TypeTag.INT;
39 import static com.sun.tools.javac.code.TypeTag.LONG;
40 import static com.sun.tools.javac.jvm.ByteCodes.*;
41 import static com.sun.tools.javac.jvm.UninitializedType.*;
42 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableEntry;
43 import java.util.Arrays;
44 import java.util.Map;
45 import java.util.HashMap;
46 import java.util.Set;
47
48 /** An internal structure that corresponds to the code attribute of
49 * methods in a classfile. The class also provides some utility operations to
50 * generate bytecode instructions.
51 *
52 * <p><b>This is NOT part of any supported API.
53 * If you write code that depends on this, you do so at your own risk.
54 * This code and its internal interfaces are subject to change or
55 * deletion without notice.</b>
56 */
57 public class Code {
58
59 public final boolean debugCode;
60 public final boolean needStackMap;
61
62 public enum StackMapFormat {
63 NONE,
64 CLDC {
65 Name getAttributeName(Names names) {
66 return names.StackMap;
171
172 /** The stack map format to be generated. */
173 StackMapFormat stackMap;
174
175 /** Switch: emit variable debug info.
176 */
177 boolean varDebugInfo;
178
179 /** Switch: emit line number info.
180 */
181 boolean lineDebugInfo;
182
183 /** Emit line number info if map supplied
184 */
185 Position.LineMap lineMap;
186
187 final MethodSymbol meth;
188
189 private int letExprStackPos = 0;
190
191 private Map<Integer, Set<VarSymbol>> cpToUnsetFieldsMap = new HashMap<>();
192
193 public Set<VarSymbol> currentUnsetFields;
194
195 boolean generateAssertUnsetFieldsFrame;
196
197 /** Construct a code object, given the settings of the fatcode,
198 * debugging info switches and the CharacterRangeTable.
199 */
200 public Code(MethodSymbol meth,
201 boolean fatcode,
202 Position.LineMap lineMap,
203 boolean varDebugInfo,
204 StackMapFormat stackMap,
205 boolean debugCode,
206 CRTable crt,
207 Symtab syms,
208 Types types,
209 PoolWriter poolWriter,
210 boolean generateAssertUnsetFieldsFrame) {
211 this.meth = meth;
212 this.fatcode = fatcode;
213 this.lineMap = lineMap;
214 this.lineDebugInfo = lineMap != null;
215 this.varDebugInfo = varDebugInfo;
216 this.crt = crt;
217 this.syms = syms;
218 this.types = types;
219 this.poolWriter = poolWriter;
220 this.debugCode = debugCode;
221 this.stackMap = stackMap;
222 switch (stackMap) {
223 case CLDC:
224 case JSR202:
225 this.needStackMap = true;
226 break;
227 default:
228 this.needStackMap = false;
229 }
230 state = new State();
231 lvar = new LocalVar[20];
232 this.generateAssertUnsetFieldsFrame = generateAssertUnsetFieldsFrame;
233 }
234
235
236 /* **************************************************************************
237 * Typecodes & related stuff
238 ****************************************************************************/
239
240 /** Given a type, return its type code (used implicitly in the
241 * JVM architecture).
242 */
243 public static int typecode(Type type) {
244 switch (type.getTag()) {
245 case BYTE: return BYTEcode;
246 case SHORT: return SHORTcode;
247 case CHAR: return CHARcode;
248 case INT: return INTcode;
249 case LONG: return LONGcode;
250 case FLOAT: return FLOATcode;
251 case DOUBLE: return DOUBLEcode;
252 case BOOLEAN: return BYTEcode;
1063 case checkcast: {
1064 state.pop(1); // object ref
1065 Type t = types.erasure((Type)data);
1066 state.push(t);
1067 break; }
1068 case ldc2:
1069 case ldc2w:
1070 state.push(types.constantType((LoadableConstant)data));
1071 break;
1072 case instanceof_:
1073 state.pop(1);
1074 state.push(syms.intType);
1075 break;
1076 case jsr:
1077 break;
1078 default:
1079 throw new AssertionError(mnem(op));
1080 }
1081 // postop();
1082 }
1083 /** Emit an opcode with a four-byte operand field.
1084 */
1085 public void emitop4(int op, int od) {
1086 emitop(op);
1087 if (!alive) return;
1088 emit4(od);
1089 switch (op) {
1090 case goto_w:
1091 markDead();
1092 break;
1093 case jsr_w:
1094 break;
1095 default:
1096 throw new AssertionError(mnem(op));
1097 }
1098 // postop();
1099 }
1100
1101 /** Align code pointer to next `incr' boundary.
1102 */
1209
1210 public int setLetExprStackPos(int pos) {
1211 int res = letExprStackPos;
1212 letExprStackPos = pos;
1213 return res;
1214 }
1215
1216 public boolean isStatementStart() {
1217 return !alive || state.stacksize == letExprStackPos;
1218 }
1219
1220 /* ************************************************************************
1221 * Stack map generation
1222 *************************************************************************/
1223
1224 /** An entry in the stack map. */
1225 static class StackMapFrame {
1226 int pc;
1227 Type[] locals;
1228 Type[] stack;
1229 Set<VarSymbol> unsetFields;
1230 }
1231
1232 /** A buffer of cldc stack map entries. */
1233 StackMapFrame[] stackMapBuffer = null;
1234
1235 /** A buffer of compressed StackMapTable entries. */
1236 StackMapTableEntry[] stackMapTableBuffer = null;
1237 int stackMapBufferSize = 0;
1238
1239 /** The last PC at which we generated a stack map. */
1240 int lastStackMapPC = -1;
1241
1242 /** The last stack map frame in StackMapTable. */
1243 StackMapFrame lastFrame = null;
1244
1245 /** The stack map frame before the last one. */
1246 StackMapFrame frameBeforeLast = null;
1247
1248 /** Emit a stack map entry. */
1249 public void emitStackMap() {
1250 int pc = curCP();
1251 if (!needStackMap) return;
1252
1253
1254
1255 switch (stackMap) {
1256 case CLDC:
1337 for (int i=0, j=0; i<localsSize; i++, j++) {
1338 Assert.check(j < localCount);
1339 frame.locals[j] = locals[i];
1340 if (width(locals[i]) > 1) i++;
1341 }
1342
1343 int stackCount = 0;
1344 for (int i=0; i<state.stacksize; i++) {
1345 if (state.stack[i] != null) {
1346 stackCount++;
1347 }
1348 }
1349 frame.stack = new Type[stackCount];
1350 stackCount = 0;
1351 for (int i=0; i<state.stacksize; i++) {
1352 if (state.stack[i] != null) {
1353 frame.stack[stackCount++] = types.erasure(state.stack[i]);
1354 }
1355 }
1356
1357 Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc);
1358 boolean generateAssertUnsetFieldsEntry = unsetFieldsAtPC != null && generateAssertUnsetFieldsFrame;
1359
1360 if (stackMapTableBuffer == null) {
1361 stackMapTableBuffer = new StackMapTableEntry[20];
1362 } else {
1363 stackMapTableBuffer = ArrayUtils.ensureCapacity(
1364 stackMapTableBuffer,
1365 stackMapBufferSize + (generateAssertUnsetFieldsEntry ? 1 : 0));
1366 }
1367
1368 if (generateAssertUnsetFieldsEntry) {
1369 if (lastFrame.unsetFields == null || !lastFrame.unsetFields.equals(unsetFieldsAtPC)) {
1370 stackMapTableBuffer[stackMapBufferSize++] = new StackMapTableEntry.AssertUnsetFields(pc, unsetFieldsAtPC);
1371 frame.unsetFields = unsetFieldsAtPC;
1372 }
1373 }
1374 stackMapTableBuffer[stackMapBufferSize++] =
1375 StackMapTableEntry.getInstance(frame, lastFrame, types, pc);
1376
1377 frameBeforeLast = lastFrame;
1378 lastFrame = frame;
1379 }
1380
1381 public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) {
1382 cpToUnsetFieldsMap.put(pc, unsetFields);
1383 }
1384
1385 StackMapFrame getInitialFrame() {
1386 StackMapFrame frame = new StackMapFrame();
1387 List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
1388 int len = arg_types.length();
1389 int count = 0;
1390 if (!meth.isStatic()) {
1391 Type thisType = meth.owner.type;
1392 frame.locals = new Type[len+1];
1393 if (meth.isConstructor() && thisType != syms.objectType) {
1394 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
1395 } else {
1396 frame.locals[count++] = types.erasure(thisType);
1397 }
1398 } else {
1399 frame.locals = new Type[len];
1400 }
1401 for (Type arg_type : arg_types) {
1402 frame.locals[count++] = types.erasure(arg_type);
1403 }
1404 frame.pc = -1;
1464 return cp - 5;
1465 } else {
1466 emitop2(opcode, 0);
1467 return cp - 3;
1468 }
1469 }
1470
1471 /** Emit a branch with given opcode; return its chain.
1472 * branch differs from jump in that jsr is treated as no-op.
1473 */
1474 public Chain branch(int opcode) {
1475 Chain result = null;
1476 if (opcode == goto_) {
1477 result = pendingJumps;
1478 pendingJumps = null;
1479 }
1480 if (opcode != dontgoto && isAlive()) {
1481 result = new Chain(emitJump(opcode),
1482 result,
1483 state.dup());
1484 if (currentUnsetFields != null) {
1485 addUnsetFieldsAtPC(result.pc, currentUnsetFields);
1486 }
1487 fixedPc = fatcode;
1488 if (opcode == goto_) alive = false;
1489 }
1490 return result;
1491 }
1492
1493 /** Resolve chain to point to given target.
1494 */
1495 public void resolve(Chain chain, int target) {
1496 boolean changed = false;
1497 State newState = state;
1498 int originalTarget = target;
1499 for (; chain != null; chain = chain.next) {
1500 Assert.check(state != chain.state
1501 && (target > chain.pc || isStatementStart()));
1502 if (target >= cp) {
1503 target = cp;
1504 } else if (get1(target) == goto_) {
1505 if (fatcode) target = target + get4(target + 1);
1506 else target = target + get2(target + 1);
1507 }
1508 if (get1(chain.pc) == goto_ &&
1509 chain.pc + 3 == target && target == cp && !fixedPc) {
1510 // If goto the next instruction, the jump is not needed:
1511 // compact the code.
1512 if (varDebugInfo) {
1513 adjustAliveRanges(cp, -3);
1514 }
1515 cp = cp - 3;
1516 target = target - 3;
1517 if (chain.next == null) {
1518 // This is the only jump to the target. Exit the loop
1519 // without setting new state. The code is reachable
1520 // from the instruction before goto_.
1521 alive = true;
1522 break;
1523 }
1524 } else {
1525 if (fatcode) {
1526 put4(chain.pc + 1, target - chain.pc);
1527 if (cpToUnsetFieldsMap.get(chain.pc) != null) {
1528 addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
1529 }
1530 }
1531 else if (target - chain.pc < Short.MIN_VALUE ||
1532 target - chain.pc > Short.MAX_VALUE)
1533 fatcode = true;
1534 else {
1535 put2(chain.pc + 1, target - chain.pc);
1536 if (cpToUnsetFieldsMap.get(chain.pc) != null) {
1537 addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
1538 }
1539 }
1540 Assert.check(!alive ||
1541 chain.state.stacksize == newState.stacksize &&
1542 chain.state.nlocks == newState.nlocks);
1543 }
1544 fixedPc = true;
1545 if (cp == target) {
1546 changed = true;
1547 if (debugCode)
1548 System.err.println("resolving chain state=" + chain.state);
1549 if (alive) {
1550 newState = chain.state.join(newState);
1551 } else {
1552 newState = chain.state;
1553 alive = true;
1554 }
1555 }
1556 }
1557 Assert.check(!changed || state != newState);
1558 if (state != newState) {
1559 setDefined(newState.defined);
|