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

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