< prev index next >

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

Print this page

   1 /*
   2  * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import com.sun.tools.javac.code.*;
  29 import com.sun.tools.javac.code.Symbol.*;
  30 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  31 import com.sun.tools.javac.util.*;
  32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  33 
  34 import java.util.function.ToIntBiFunction;
  35 import java.util.function.ToIntFunction;
  36 
  37 import static com.sun.tools.javac.code.TypeTag.BOT;
  38 import static com.sun.tools.javac.code.TypeTag.DOUBLE;
  39 import static com.sun.tools.javac.code.TypeTag.INT;
  40 import static com.sun.tools.javac.code.TypeTag.LONG;
  41 import static com.sun.tools.javac.jvm.ByteCodes.*;
  42 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
  43 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
  44 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
  45 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
  46 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
  47 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
  48 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
  49 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
  50 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
  51 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
  52 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
  53 import static com.sun.tools.javac.jvm.UninitializedType.*;
  54 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
  55 import java.util.Arrays;



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

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






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

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

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

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

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

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

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



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







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




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

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);
< prev index next >