< prev index next >

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

Print this page

  60  *  <p><b>This is NOT part of any supported API.
  61  *  If you write code that depends on this, you do so at your own risk.
  62  *  This code and its internal interfaces are subject to change or
  63  *  deletion without notice.</b>
  64  */
  65 public class Gen extends JCTree.Visitor {
  66     protected static final Context.Key<Gen> genKey = new Context.Key<>();
  67 
  68     private final Log log;
  69     private final Symtab syms;
  70     private final Check chk;
  71     private final Resolve rs;
  72     private final TreeMaker make;
  73     private final Names names;
  74     private final Target target;
  75     private final String accessDollar;
  76     private final Types types;
  77     private final Lower lower;
  78     private final Annotate annotate;
  79     private final StringConcat concat;

  80 
  81     /** Format of stackmap tables to be generated. */
  82     private final Code.StackMapFormat stackMap;
  83 
  84     /** A type that serves as the expected type for all method expressions.
  85      */
  86     private final Type methodType;
  87 
  88     public static Gen instance(Context context) {
  89         Gen instance = context.get(genKey);
  90         if (instance == null)
  91             instance = new Gen(context);
  92         return instance;
  93     }
  94 
  95     /** Constant pool writer, set by genClass.
  96      */
  97     final PoolWriter poolWriter;
  98 
  99     @SuppressWarnings("this-escape")
 100     protected Gen(Context context) {
 101         context.put(genKey, this);
 102 
 103         names = Names.instance(context);
 104         log = Log.instance(context);
 105         syms = Symtab.instance(context);
 106         chk = Check.instance(context);
 107         rs = Resolve.instance(context);
 108         make = TreeMaker.instance(context);
 109         target = Target.instance(context);
 110         types = Types.instance(context);
 111         concat = StringConcat.instance(context);

 112 
 113         methodType = new MethodType(null, null, null, syms.methodClass);
 114         accessDollar = "access" + target.syntheticNameChar();
 115         lower = Lower.instance(context);
 116 
 117         Options options = Options.instance(context);
 118         lineDebugInfo =
 119             options.isUnset(G_CUSTOM) ||
 120             options.isSet(G_CUSTOM, "lines");
 121         varDebugInfo =
 122             options.isUnset(G_CUSTOM)
 123             ? options.isSet(G)
 124             : options.isSet(G_CUSTOM, "vars");
 125         genCrt = options.isSet(XJCOV);
 126         debugCode = options.isSet("debug.code");
 127         disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
 128         poolWriter = new PoolWriter(types, names);
 129 
 130         // ignore cldc because we cannot have both stackmap formats
 131         this.stackMap = StackMapFormat.JSR202;
 132         annotate = Annotate.instance(context);
 133         qualifiedSymbolCache = new HashMap<>();



 134     }
 135 
 136     /** Switches
 137      */
 138     private final boolean lineDebugInfo;
 139     private final boolean varDebugInfo;
 140     private final boolean genCrt;
 141     private final boolean debugCode;
 142     private boolean disableVirtualizedPrivateInvoke;

 143 
 144     /** Code buffer, set by genMethod.
 145      */
 146     private Code code;
 147 
 148     /** Items structure, set by genMethod.
 149      */
 150     private Items items;
 151 
 152     /** Environment for symbol lookup, set by genClass
 153      */
 154     private Env<AttrContext> attrEnv;
 155 
 156     /** The top level tree.
 157      */
 158     private JCCompilationUnit toplevel;
 159 
 160     /** The number of code-gen errors in this class.
 161      */
 162     private int nerrs = 0;

 396     /** Do any of the structures aborted by a non-local exit have
 397      *  finalizers that require an empty stack?
 398      *  @param target      The tree representing the structure that's aborted
 399      *  @param env         The environment current at the non-local exit.
 400      */
 401     boolean hasFinally(JCTree target, Env<GenContext> env) {
 402         while (env.tree != target) {
 403             if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer())
 404                 return true;
 405             env = env.next;
 406         }
 407         return false;
 408     }
 409 
 410 /* ************************************************************************
 411  * Normalizing class-members.
 412  *************************************************************************/
 413 
 414     /** Distribute member initializer code into constructors and {@code <clinit>}
 415      *  method.
 416      *  @param defs         The list of class member declarations.
 417      *  @param c            The enclosing class.
 418      */
 419     List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) {
 420         ListBuffer<JCStatement> initCode = new ListBuffer<>();


 421         ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>();
 422         ListBuffer<JCStatement> clinitCode = new ListBuffer<>();
 423         ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>();
 424         ListBuffer<JCTree> methodDefs = new ListBuffer<>();
 425         // Sort definitions into three listbuffers:
 426         //  - initCode for instance initializers
 427         //  - clinitCode for class initializers
 428         //  - methodDefs for method definitions
 429         for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) {
 430             JCTree def = l.head;
 431             switch (def.getTag()) {
 432             case BLOCK:
 433                 JCBlock block = (JCBlock)def;
 434                 if ((block.flags & STATIC) != 0)
 435                     clinitCode.append(block);
 436                 else if ((block.flags & SYNTHETIC) == 0)
 437                     initCode.append(block);





 438                 break;
 439             case METHODDEF:
 440                 methodDefs.append(def);
 441                 break;
 442             case VARDEF:
 443                 JCVariableDecl vdef = (JCVariableDecl) def;
 444                 VarSymbol sym = vdef.sym;
 445                 checkDimension(vdef.pos(), sym.type);
 446                 if (vdef.init != null) {
 447                     if ((sym.flags() & STATIC) == 0) {
 448                         // Always initialize instance variables.
 449                         JCStatement init = make.at(vdef.pos()).
 450                             Assignment(sym, vdef.init);
 451                         initCode.append(init);
 452                         init.endpos = vdef.endpos;
 453                         initTAs.addAll(getAndRemoveNonFieldTAs(sym));
 454                     } else if (sym.getConstValue() == null) {
 455                         // Initialize class (static) variables only if
 456                         // they are not compile-time constants.
 457                         JCStatement init = make.at(vdef.pos).
 458                             Assignment(sym, vdef.init);
 459                         clinitCode.append(init);
 460                         init.endpos = vdef.endpos;
 461                         clinitTAs.addAll(getAndRemoveNonFieldTAs(sym));
 462                     } else {
 463                         checkStringConstant(vdef.init.pos(), sym.getConstValue());
 464                         /* if the init contains a reference to an external class, add it to the
 465                          * constant's pool
 466                          */
 467                         vdef.init.accept(classReferenceVisitor);
 468                     }
 469                 }
 470                 break;
 471             default:
 472                 Assert.error();
 473             }
 474         }
 475         // Insert any instance initializers into all constructors.
 476         if (initCode.length() != 0) {
 477             List<JCStatement> inits = initCode.toList();
 478             initTAs.addAll(c.getInitTypeAttributes());
 479             List<Attribute.TypeCompound> initTAlist = initTAs.toList();
 480             for (JCTree t : methodDefs) {
 481                 normalizeMethod((JCMethodDecl)t, inits, initTAlist);
 482             }
 483         }




 484         // If there are class initializers, create a <clinit> method
 485         // that contains them as its body.
 486         if (clinitCode.length() != 0) {
 487             MethodSymbol clinit = new MethodSymbol(
 488                 STATIC | (c.flags() & STRICTFP),
 489                 names.clinit,
 490                 new MethodType(
 491                     List.nil(), syms.voidType,
 492                     List.nil(), syms.methodClass),
 493                 c);
 494             c.members().enter(clinit);
 495             List<JCStatement> clinitStats = clinitCode.toList();
 496             JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
 497             block.bracePos = TreeInfo.endPos(clinitStats.last());
 498             methodDefs.append(make.MethodDef(clinit, block));
 499 
 500             if (!clinitTAs.isEmpty())
 501                 clinit.appendUniqueTypeAttributes(clinitTAs.toList());
 502             if (!c.getClassInitTypeAttributes().isEmpty())
 503                 clinit.appendUniqueTypeAttributes(c.getClassInitTypeAttributes());
 504         }
 505         // Return all method definitions.
 506         return methodDefs.toList();
 507     }
 508 
 509     private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) {
 510         List<TypeCompound> tas = sym.getRawTypeAttributes();
 511         ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>();
 512         ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>();
 513         for (TypeCompound ta : tas) {
 514             Assert.check(ta.getPosition().type != TargetType.UNKNOWN);
 515             if (ta.getPosition().type == TargetType.FIELD) {
 516                 fieldTAs.add(ta);
 517             } else {
 518                 nonfieldTAs.add(ta);
 519             }
 520         }
 521         sym.setTypeAttributes(fieldTAs.toList());
 522         return nonfieldTAs.toList();
 523     }
 524 
 525     /** Check a constant value and report if it is a string that is
 526      *  too large.
 527      */
 528     private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
 529         if (nerrs != 0 || // only complain about a long string once
 530             constValue == null ||
 531             !(constValue instanceof String str) ||
 532             str.length() < PoolWriter.MAX_STRING_LENGTH)
 533             return;
 534         log.error(pos, Errors.LimitString);
 535         nerrs++;
 536     }
 537 
 538     /** Insert instance initializer code into constructors prior to the super() call.
 539      *  @param md        The tree potentially representing a
 540      *                   constructor's definition.
 541      *  @param initCode  The list of instance initializer statements.
 542      *  @param initTAs  Type annotations from the initializer expression.
 543      */
 544     void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
 545         if (TreeInfo.isConstructor(md) && TreeInfo.hasConstructorCall(md, names._super)) {
 546             // We are seeing a constructor that has a super() call.
 547             // Find the super() invocation and append the given initializer code.
 548             TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall)));












 549 
 550             if (md.body.bracePos == Position.NOPOS)
 551                 md.body.bracePos = TreeInfo.endPos(md.body.stats.last());


 552 
 553             md.sym.appendUniqueTypeAttributes(initTAs);
























 554         }
 555     }
 556 
 557 /* ************************************************************************
 558  * Traversal methods
 559  *************************************************************************/
 560 
 561     /** Visitor argument: The current environment.
 562      */
 563     Env<GenContext> env;
 564 
 565     /** Visitor argument: The expected type (prototype).
 566      */
 567     Type pt;
 568 
 569     /** Visitor result: The item representing the computed value.
 570      */
 571     Item result;
 572 
 573     /** Visitor method: generate code for a definition, catching and reporting

 999                 code.compressCatchTable();
1000 
1001                 // Fill in type annotation positions for exception parameters
1002                 code.fillExceptionParameterPositions();
1003             }
1004         }
1005 
1006         private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1007             MethodSymbol meth = tree.sym;
1008 
1009             // Create a new code structure.
1010             meth.code = code = new Code(meth,
1011                                         fatcode,
1012                                         lineDebugInfo ? toplevel.lineMap : null,
1013                                         varDebugInfo,
1014                                         stackMap,
1015                                         debugCode,
1016                                         genCrt ? new CRTable(tree) : null,
1017                                         syms,
1018                                         types,
1019                                         poolWriter);

1020             items = new Items(poolWriter, code, syms, types);
1021             if (code.debugCode) {
1022                 System.err.println(meth + " for body " + tree);
1023             }
1024 
1025             // If method is not static, create a new local variable address
1026             // for `this'.
1027             if ((tree.mods.flags & STATIC) == 0) {
1028                 Type selfType = meth.owner.type;
1029                 if (meth.isConstructor() && selfType != syms.objectType)
1030                     selfType = UninitializedType.uninitializedThis(selfType);
1031                 code.setDefined(
1032                         code.newLocal(
1033                             new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1034             }
1035 
1036             // Mark all parameters as defined from the beginning of
1037             // the method.
1038             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1039                 checkDimension(l.head.pos(), l.head.sym.type);
1040                 code.setDefined(code.newLocal(l.head.sym));
1041             }
1042 




1043             // Get ready to generate code for method body.
1044             int startpcCrt = genCrt ? code.curCP() : 0;
1045             code.entryPoint();
1046 
1047             // Suppress initial stackmap
1048             code.pendingStackMap = false;
1049 
1050             return startpcCrt;
1051         }
1052 
1053     public void visitVarDef(JCVariableDecl tree) {
1054         VarSymbol v = tree.sym;
1055         if (tree.init != null) {
1056             checkStringConstant(tree.init.pos(), v.getConstValue());
1057             if (v.getConstValue() == null || varDebugInfo) {
1058                 Assert.check(code.isStatementStart());
1059                 code.newLocal(v);
1060                 genExpr(tree.init, v.erasure(types)).load();
1061                 items.makeLocalItem(v).store();
1062                 Assert.check(code.isStatementStart());

1135     public void visitForLoop(JCForLoop tree) {
1136         int limit = code.nextreg;
1137         genStats(tree.init, env);
1138         genLoop(tree, tree.body, tree.cond, tree.step, true);
1139         code.endScopes(limit);
1140     }
1141     //where
1142         /** Generate code for a loop.
1143          *  @param loop       The tree representing the loop.
1144          *  @param body       The loop's body.
1145          *  @param cond       The loop's controlling condition.
1146          *  @param step       "Step" statements to be inserted at end of
1147          *                    each iteration.
1148          *  @param testFirst  True if the loop test belongs before the body.
1149          */
1150         private void genLoop(JCStatement loop,
1151                              JCStatement body,
1152                              JCExpression cond,
1153                              List<JCExpressionStatement> step,
1154                              boolean testFirst) {








1155             Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1156             int startpc = code.entryPoint();
1157             if (testFirst) { //while or for loop
1158                 CondItem c;
1159                 if (cond != null) {
1160                     code.statBegin(cond.pos);
1161                     Assert.check(code.isStatementStart());
1162                     c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1163                 } else {
1164                     c = items.makeCondItem(goto_);
1165                 }
1166                 Chain loopDone = c.jumpFalse();
1167                 code.resolve(c.trueJumps);
1168                 Assert.check(code.isStatementStart());
1169                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1170                 code.resolve(loopEnv.info.cont);
1171                 genStats(step, loopEnv);
1172                 code.resolve(code.branch(goto_), startpc);
1173                 code.resolve(loopDone);
1174             } else {

1273                     hasTry = true;
1274                 }
1275 
1276                 @Override
1277                 public void visitClassDef(JCClassDecl tree) {
1278                 }
1279 
1280                 @Override
1281                 public void visitLambda(JCLambda tree) {
1282                 }
1283             };
1284 
1285             HasTryScanner hasTryScanner = new HasTryScanner();
1286 
1287             hasTryScanner.scan(tree);
1288             return hasTryScanner.hasTry;
1289         }
1290 
1291     private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases,
1292                               boolean patternSwitch) {





1293         int limit = code.nextreg;
1294         Assert.check(!selector.type.hasTag(CLASS));
1295         int switchStart = patternSwitch ? code.entryPoint() : -1;
1296         int startpcCrt = genCrt ? code.curCP() : 0;
1297         Assert.check(code.isStatementStart());
1298         Item sel = genExpr(selector, syms.intType);
1299         if (cases.isEmpty()) {
1300             // We are seeing:  switch <sel> {}
1301             sel.load().drop();
1302             if (genCrt)
1303                 code.crt.put(TreeInfo.skipParens(selector),
1304                              CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1305         } else {
1306             // We are seeing a nonempty switch.
1307             sel.load();
1308             if (genCrt)
1309                 code.crt.put(TreeInfo.skipParens(selector),
1310                              CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1311             Env<GenContext> switchEnv = env.dup(swtch, new GenContext());
1312             switchEnv.info.isSwitch = true;

1521             @Override
1522             void afterBody() {
1523                 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) {
1524                     //for body-only finally, remove the GenFinalizer after try body
1525                     //so that the finally is not generated to catch bodies:
1526                     tryEnv.info.finalize = null;
1527                 }
1528             }
1529 
1530         };
1531         tryEnv.info.gaps = new ListBuffer<>();
1532         genTry(tree.body, tree.catchers, tryEnv);
1533     }
1534     //where
1535         /** Generate code for a try or synchronized statement
1536          *  @param body      The body of the try or synchronized statement.
1537          *  @param catchers  The list of catch clauses.
1538          *  @param env       The current environment of the body.
1539          */
1540         void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {




1541             int limit = code.nextreg;
1542             int startpc = code.curCP();
1543             Code.State stateTry = code.state.dup();
1544             genStat(body, env, CRT_BLOCK);
1545             int endpc = code.curCP();
1546             List<Integer> gaps = env.info.gaps.toList();
1547             code.statBegin(TreeInfo.endPos(body));
1548             genFinalizer(env);
1549             code.statBegin(TreeInfo.endPos(env.tree));
1550             Chain exitChain;
1551             boolean actualTry = env.tree.hasTag(TRY);
1552             if (startpc == endpc && actualTry) {
1553                 exitChain = code.branch(dontgoto);
1554             } else {
1555                 exitChain = code.branch(goto_);
1556             }
1557             endFinalizerGap(env);
1558             env.info.finalize.afterBody();
1559             boolean hasFinalizer =
1560                 env.info.finalize != null &&

1732         /** Register a catch clause in the "Exceptions" code-attribute.
1733          */
1734         void registerCatch(DiagnosticPosition pos,
1735                            int startpc, int endpc,
1736                            int handler_pc, int catch_type) {
1737             char startpc1 = (char)startpc;
1738             char endpc1 = (char)endpc;
1739             char handler_pc1 = (char)handler_pc;
1740             if (startpc1 == startpc &&
1741                 endpc1 == endpc &&
1742                 handler_pc1 == handler_pc) {
1743                 code.addCatch(startpc1, endpc1, handler_pc1,
1744                               (char)catch_type);
1745             } else {
1746                 log.error(pos, Errors.LimitCodeTooLargeForTryStmt);
1747                 nerrs++;
1748             }
1749         }
1750 
1751     public void visitIf(JCIf tree) {




1752         int limit = code.nextreg;
1753         Chain thenExit = null;
1754         Assert.check(code.isStatementStart());
1755         CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1756                              CRT_FLOW_CONTROLLER);
1757         Chain elseChain = c.jumpFalse();
1758         Assert.check(code.isStatementStart());
1759         if (!c.isFalse()) {
1760             code.resolve(c.trueJumps);
1761             genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1762             thenExit = code.branch(goto_);
1763         }
1764         if (elseChain != null) {
1765             code.resolve(elseChain);
1766             if (tree.elsepart != null) {
1767                 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
1768             }
1769         }
1770         code.resolve(thenExit);
1771         code.endScopes(limit);

2452     }
2453 
2454 /* ************************************************************************
2455  * main method
2456  *************************************************************************/
2457 
2458     /** Generate code for a class definition.
2459      *  @param env   The attribution environment that belongs to the
2460      *               outermost class containing this class definition.
2461      *               We need this for resolving some additional symbols.
2462      *  @param cdef  The tree representing the class definition.
2463      *  @return      True if code is generated with no errors.
2464      */
2465     public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2466         try {
2467             attrEnv = env;
2468             ClassSymbol c = cdef.sym;
2469             this.toplevel = env.toplevel;
2470             /* method normalizeDefs() can add references to external classes into the constant pool
2471              */
2472             cdef.defs = normalizeDefs(cdef.defs, c);
2473             generateReferencesToPrunedTree(c);
2474             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2475             localEnv.toplevel = env.toplevel;
2476             localEnv.enclClass = cdef;
2477 
2478             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2479                 genDef(l.head, localEnv);
2480             }
2481             if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2482                 log.error(cdef.pos(), Errors.LimitPool);
2483                 nerrs++;
2484             }
2485             if (nerrs != 0) {
2486                 // if errors, discard code
2487                 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2488                     if (l.head.hasTag(METHODDEF))
2489                         ((JCMethodDecl) l.head).sym.code = null;
2490                 }
2491             }
2492             cdef.defs = List.nil(); // discard trees

  60  *  <p><b>This is NOT part of any supported API.
  61  *  If you write code that depends on this, you do so at your own risk.
  62  *  This code and its internal interfaces are subject to change or
  63  *  deletion without notice.</b>
  64  */
  65 public class Gen extends JCTree.Visitor {
  66     protected static final Context.Key<Gen> genKey = new Context.Key<>();
  67 
  68     private final Log log;
  69     private final Symtab syms;
  70     private final Check chk;
  71     private final Resolve rs;
  72     private final TreeMaker make;
  73     private final Names names;
  74     private final Target target;
  75     private final String accessDollar;
  76     private final Types types;
  77     private final Lower lower;
  78     private final Annotate annotate;
  79     private final StringConcat concat;
  80     private final LocalProxyVarsGen localProxyVarsGen;
  81 
  82     /** Format of stackmap tables to be generated. */
  83     private final Code.StackMapFormat stackMap;
  84 
  85     /** A type that serves as the expected type for all method expressions.
  86      */
  87     private final Type methodType;
  88 
  89     public static Gen instance(Context context) {
  90         Gen instance = context.get(genKey);
  91         if (instance == null)
  92             instance = new Gen(context);
  93         return instance;
  94     }
  95 
  96     /** Constant pool writer, set by genClass.
  97      */
  98     final PoolWriter poolWriter;
  99 
 100     @SuppressWarnings("this-escape")
 101     protected Gen(Context context) {
 102         context.put(genKey, this);
 103 
 104         names = Names.instance(context);
 105         log = Log.instance(context);
 106         syms = Symtab.instance(context);
 107         chk = Check.instance(context);
 108         rs = Resolve.instance(context);
 109         make = TreeMaker.instance(context);
 110         target = Target.instance(context);
 111         types = Types.instance(context);
 112         concat = StringConcat.instance(context);
 113         localProxyVarsGen = LocalProxyVarsGen.instance(context);
 114 
 115         methodType = new MethodType(null, null, null, syms.methodClass);
 116         accessDollar = "access" + target.syntheticNameChar();
 117         lower = Lower.instance(context);
 118 
 119         Options options = Options.instance(context);
 120         lineDebugInfo =
 121             options.isUnset(G_CUSTOM) ||
 122             options.isSet(G_CUSTOM, "lines");
 123         varDebugInfo =
 124             options.isUnset(G_CUSTOM)
 125             ? options.isSet(G)
 126             : options.isSet(G_CUSTOM, "vars");
 127         genCrt = options.isSet(XJCOV);
 128         debugCode = options.isSet("debug.code");
 129         disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
 130         poolWriter = new PoolWriter(types, names);
 131 
 132         // ignore cldc because we cannot have both stackmap formats
 133         this.stackMap = StackMapFormat.JSR202;
 134         annotate = Annotate.instance(context);
 135         qualifiedSymbolCache = new HashMap<>();
 136         Preview preview = Preview.instance(context);
 137         Source source = Source.instance(context);
 138         allowValueClasses = preview.isEnabled() && Source.Feature.VALUE_CLASSES.allowedInSource(source);
 139     }
 140 
 141     /** Switches
 142      */
 143     private final boolean lineDebugInfo;
 144     private final boolean varDebugInfo;
 145     private final boolean genCrt;
 146     private final boolean debugCode;
 147     private boolean disableVirtualizedPrivateInvoke;
 148     private final boolean allowValueClasses;
 149 
 150     /** Code buffer, set by genMethod.
 151      */
 152     private Code code;
 153 
 154     /** Items structure, set by genMethod.
 155      */
 156     private Items items;
 157 
 158     /** Environment for symbol lookup, set by genClass
 159      */
 160     private Env<AttrContext> attrEnv;
 161 
 162     /** The top level tree.
 163      */
 164     private JCCompilationUnit toplevel;
 165 
 166     /** The number of code-gen errors in this class.
 167      */
 168     private int nerrs = 0;

 402     /** Do any of the structures aborted by a non-local exit have
 403      *  finalizers that require an empty stack?
 404      *  @param target      The tree representing the structure that's aborted
 405      *  @param env         The environment current at the non-local exit.
 406      */
 407     boolean hasFinally(JCTree target, Env<GenContext> env) {
 408         while (env.tree != target) {
 409             if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer())
 410                 return true;
 411             env = env.next;
 412         }
 413         return false;
 414     }
 415 
 416 /* ************************************************************************
 417  * Normalizing class-members.
 418  *************************************************************************/
 419 
 420     /** Distribute member initializer code into constructors and {@code <clinit>}
 421      *  method.
 422      *  @param classDecl         The class declaration to normalize.

 423      */
 424     List<JCTree> normalizeDefs(JCClassDecl classDecl) {
 425         ListBuffer<JCStatement> initCode = new ListBuffer<>();
 426         // only used for value classes
 427         ListBuffer<JCStatement> initBlocks = new ListBuffer<>();
 428         ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>();
 429         ListBuffer<JCStatement> clinitCode = new ListBuffer<>();
 430         ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>();
 431         ListBuffer<JCTree> methodDefs = new ListBuffer<>();
 432         // Sort definitions into three listbuffers:
 433         //  - initCode for instance initializers
 434         //  - clinitCode for class initializers
 435         //  - methodDefs for method definitions
 436         for (List<JCTree> l = classDecl.defs; l.nonEmpty(); l = l.tail) {
 437             JCTree def = l.head;
 438             switch (def.getTag()) {
 439             case BLOCK:
 440                 JCBlock block = (JCBlock)def;
 441                 if ((block.flags & STATIC) != 0)
 442                     clinitCode.append(block);
 443                 else if ((block.flags & SYNTHETIC) == 0) {
 444                     if (classDecl.sym.isValueClass()) {
 445                         initBlocks.append(block);
 446                     } else {
 447                         initCode.append(block);
 448                     }
 449                 }
 450                 break;
 451             case METHODDEF:
 452                 methodDefs.append(def);
 453                 break;
 454             case VARDEF:
 455                 JCVariableDecl vdef = (JCVariableDecl) def;
 456                 VarSymbol sym = vdef.sym;
 457                 checkDimension(vdef.pos(), sym.type);
 458                 if (vdef.init != null) {
 459                     if ((sym.flags() & STATIC) == 0) {
 460                         // Always initialize instance variables.
 461                         JCStatement init = make.at(vdef.pos()).
 462                             Assignment(sym, vdef.init);
 463                         initCode.append(init);
 464                         init.endpos = vdef.endpos;
 465                         initTAs.addAll(getAndRemoveNonFieldTAs(sym));
 466                     } else if (sym.getConstValue() == null) {
 467                         // Initialize class (static) variables only if
 468                         // they are not compile-time constants.
 469                         JCStatement init = make.at(vdef.pos).
 470                             Assignment(sym, vdef.init);
 471                         clinitCode.append(init);
 472                         init.endpos = vdef.endpos;
 473                         clinitTAs.addAll(getAndRemoveNonFieldTAs(sym));
 474                     } else {
 475                         checkStringConstant(vdef.init.pos(), sym.getConstValue());
 476                         /* if the init contains a reference to an external class, add it to the
 477                          * constant's pool
 478                          */
 479                         vdef.init.accept(classReferenceVisitor);
 480                     }
 481                 }
 482                 break;
 483             default:
 484                 Assert.error();
 485             }
 486         }
 487         // Insert any instance initializers into all constructors.
 488         List<TypeCompound> initTAlist = List.nil();
 489         if (initCode.nonEmpty() || initBlocks.nonEmpty()) {
 490             initTAs.addAll(classDecl.sym.getInitTypeAttributes());
 491             initTAlist = initTAs.toList();



 492         }
 493         for (JCTree t : methodDefs) {
 494             normalizeMethod((JCMethodDecl)t, initCode.toList(), initBlocks.toList(), initTAlist);
 495         }
 496         localProxyVarsGen.allFieldNormalized(classDecl.sym);
 497         // If there are class initializers, create a <clinit> method
 498         // that contains them as its body.
 499         if (clinitCode.length() != 0) {
 500             MethodSymbol clinit = new MethodSymbol(
 501                 STATIC | (classDecl.sym.flags() & STRICTFP),
 502                 names.clinit,
 503                 new MethodType(
 504                     List.nil(), syms.voidType,
 505                     List.nil(), syms.methodClass),
 506                     classDecl.sym);
 507             classDecl.sym.members().enter(clinit);
 508             List<JCStatement> clinitStats = clinitCode.toList();
 509             JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
 510             block.bracePos = TreeInfo.endPos(clinitStats.last());
 511             methodDefs.append(make.MethodDef(clinit, block));
 512 
 513             if (!clinitTAs.isEmpty())
 514                 clinit.appendUniqueTypeAttributes(clinitTAs.toList());
 515             if (!classDecl.sym.getClassInitTypeAttributes().isEmpty())
 516                 clinit.appendUniqueTypeAttributes(classDecl.sym.getClassInitTypeAttributes());
 517         }
 518         // Return all method definitions.
 519         return methodDefs.toList();
 520     }
 521 
 522     private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) {
 523         List<TypeCompound> tas = sym.getRawTypeAttributes();
 524         ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>();
 525         ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>();
 526         for (TypeCompound ta : tas) {
 527             Assert.check(ta.getPosition().type != TargetType.UNKNOWN);
 528             if (ta.getPosition().type == TargetType.FIELD) {
 529                 fieldTAs.add(ta);
 530             } else {
 531                 nonfieldTAs.add(ta);
 532             }
 533         }
 534         sym.setTypeAttributes(fieldTAs.toList());
 535         return nonfieldTAs.toList();
 536     }
 537 
 538     /** Check a constant value and report if it is a string that is
 539      *  too large.
 540      */
 541     private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
 542         if (nerrs != 0 || // only complain about a long string once
 543             constValue == null ||
 544             !(constValue instanceof String str) ||
 545             str.length() < PoolWriter.MAX_STRING_LENGTH)
 546             return;
 547         log.error(pos, Errors.LimitString);
 548         nerrs++;
 549     }
 550 
 551     /** Insert instance initializer code into constructors prior to the super() call.
 552      *  @param md        The tree potentially representing a
 553      *                   constructor's definition.
 554      *  @param initCode  The list of instance initializer statements.
 555      *  @param initTAs  Type annotations from the initializer expression.
 556      */
 557     void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<JCStatement> initBlocks,  List<TypeCompound> initTAs) {
 558         if (TreeInfo.isConstructor(md) && TreeInfo.hasConstructorCall(md, names._super)) {
 559             // We are seeing a constructor that has a super() call.
 560             // Find the super() invocation and append the given initializer code.
 561             if (initCode.nonEmpty() || initBlocks.nonEmpty()) {
 562                 if (allowValueClasses &&
 563                         (md.sym.owner.isValueClass() || ((md.sym.owner.flags_field & RECORD) != 0))) {
 564                     rewriteEarlyInitializersIfNeeded(md, initCode);
 565                     md.body.stats = initCode.appendList(md.body.stats);
 566                     TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initBlocks.prepend(supercall)));
 567                 } else {
 568                     TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall)));
 569                 }
 570                 md.sym.appendUniqueTypeAttributes(initTAs);
 571             }
 572 
 573             localProxyVarsGen.patchConstructor(md, make);
 574 
 575             if (md.body.bracePos == Position.NOPOS)
 576                 md.body.bracePos = TreeInfo.endPos(md.body.stats.last());
 577         }
 578     }
 579 
 580     /**
 581      * Some early field initializer might contain references to synthetic Lower symbols,
 582      * such as 'this$0' or local var proxies. Since these are effectively "early reads",
 583      * we need to replace such reference with a reference to the corresponding
 584      * (synthetic) constructor parameter.
 585      */
 586     void rewriteEarlyInitializersIfNeeded(JCMethodDecl md, List<JCStatement> initCode) {
 587         class EarlyInitializerVisitor extends TreeScanner {
 588             @Override
 589             public void visitIdent(JCIdent tree) {
 590                 if ((tree.sym.flags() & OUTER_THIS_FIELD) != 0) {
 591                     tree.sym = md.sym.extraParams.head;
 592                 } else if ((tree.sym.flags() & LOCAL_CAPTURE_FIELD) != 0) {
 593                     Symbol capturedSym = tree.sym.baseSymbol();
 594                     tree.sym = md.sym.capturedLocals.stream()
 595                             .filter(l -> l.baseSymbol() == capturedSym)
 596                             .findAny().orElseThrow();
 597                 }
 598             }
 599         }
 600         if (md.sym.capturedLocals.nonEmpty() || md.sym.extraParams.nonEmpty()) {
 601             EarlyInitializerVisitor initializerVisitor = new EarlyInitializerVisitor();
 602             for (JCStatement init : initCode) {
 603                 initializerVisitor.scan(init);
 604             }
 605         }
 606     }
 607 
 608 /* ************************************************************************
 609  * Traversal methods
 610  *************************************************************************/
 611 
 612     /** Visitor argument: The current environment.
 613      */
 614     Env<GenContext> env;
 615 
 616     /** Visitor argument: The expected type (prototype).
 617      */
 618     Type pt;
 619 
 620     /** Visitor result: The item representing the computed value.
 621      */
 622     Item result;
 623 
 624     /** Visitor method: generate code for a definition, catching and reporting

1050                 code.compressCatchTable();
1051 
1052                 // Fill in type annotation positions for exception parameters
1053                 code.fillExceptionParameterPositions();
1054             }
1055         }
1056 
1057         private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1058             MethodSymbol meth = tree.sym;
1059 
1060             // Create a new code structure.
1061             meth.code = code = new Code(meth,
1062                                         fatcode,
1063                                         lineDebugInfo ? toplevel.lineMap : null,
1064                                         varDebugInfo,
1065                                         stackMap,
1066                                         debugCode,
1067                                         genCrt ? new CRTable(tree) : null,
1068                                         syms,
1069                                         types,
1070                                         poolWriter,
1071                                         allowValueClasses);
1072             items = new Items(poolWriter, code, syms, types);
1073             if (code.debugCode) {
1074                 System.err.println(meth + " for body " + tree);
1075             }
1076 
1077             // If method is not static, create a new local variable address
1078             // for `this'.
1079             if ((tree.mods.flags & STATIC) == 0) {
1080                 Type selfType = meth.owner.type;
1081                 if (meth.isConstructor() && selfType != syms.objectType)
1082                     selfType = UninitializedType.uninitializedThis(selfType);
1083                 code.setDefined(
1084                         code.newLocal(
1085                             new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1086             }
1087 
1088             // Mark all parameters as defined from the beginning of
1089             // the method.
1090             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1091                 checkDimension(l.head.pos(), l.head.sym.type);
1092                 code.setDefined(code.newLocal(l.head.sym));
1093             }
1094 
1095             if (allowValueClasses && meth.isConstructor()) {
1096                 code.initUnsetStrictFields(env.enclClass.sym);
1097             }
1098 
1099             // Get ready to generate code for method body.
1100             int startpcCrt = genCrt ? code.curCP() : 0;
1101             code.entryPoint();
1102 
1103             // Suppress initial stackmap
1104             code.pendingStackMap = false;
1105 
1106             return startpcCrt;
1107         }
1108 
1109     public void visitVarDef(JCVariableDecl tree) {
1110         VarSymbol v = tree.sym;
1111         if (tree.init != null) {
1112             checkStringConstant(tree.init.pos(), v.getConstValue());
1113             if (v.getConstValue() == null || varDebugInfo) {
1114                 Assert.check(code.isStatementStart());
1115                 code.newLocal(v);
1116                 genExpr(tree.init, v.erasure(types)).load();
1117                 items.makeLocalItem(v).store();
1118                 Assert.check(code.isStatementStart());

1191     public void visitForLoop(JCForLoop tree) {
1192         int limit = code.nextreg;
1193         genStats(tree.init, env);
1194         genLoop(tree, tree.body, tree.cond, tree.step, true);
1195         code.endScopes(limit);
1196     }
1197     //where
1198         /** Generate code for a loop.
1199          *  @param loop       The tree representing the loop.
1200          *  @param body       The loop's body.
1201          *  @param cond       The loop's controlling condition.
1202          *  @param step       "Step" statements to be inserted at end of
1203          *                    each iteration.
1204          *  @param testFirst  True if the loop test belongs before the body.
1205          */
1206         private void genLoop(JCStatement loop,
1207                              JCStatement body,
1208                              JCExpression cond,
1209                              List<JCExpressionStatement> step,
1210                              boolean testFirst) {
1211             genLoopHelper(loop, body, cond, step, testFirst);
1212         }
1213 
1214         private void genLoopHelper(JCStatement loop,
1215                              JCStatement body,
1216                              JCExpression cond,
1217                              List<JCExpressionStatement> step,
1218                              boolean testFirst) {
1219             Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1220             int startpc = code.entryPoint();
1221             if (testFirst) { //while or for loop
1222                 CondItem c;
1223                 if (cond != null) {
1224                     code.statBegin(cond.pos);
1225                     Assert.check(code.isStatementStart());
1226                     c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1227                 } else {
1228                     c = items.makeCondItem(goto_);
1229                 }
1230                 Chain loopDone = c.jumpFalse();
1231                 code.resolve(c.trueJumps);
1232                 Assert.check(code.isStatementStart());
1233                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1234                 code.resolve(loopEnv.info.cont);
1235                 genStats(step, loopEnv);
1236                 code.resolve(code.branch(goto_), startpc);
1237                 code.resolve(loopDone);
1238             } else {

1337                     hasTry = true;
1338                 }
1339 
1340                 @Override
1341                 public void visitClassDef(JCClassDecl tree) {
1342                 }
1343 
1344                 @Override
1345                 public void visitLambda(JCLambda tree) {
1346                 }
1347             };
1348 
1349             HasTryScanner hasTryScanner = new HasTryScanner();
1350 
1351             hasTryScanner.scan(tree);
1352             return hasTryScanner.hasTry;
1353         }
1354 
1355     private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases,
1356                               boolean patternSwitch) {
1357         handleSwitchHelper(swtch, selector, cases, patternSwitch);
1358     }
1359 
1360     void handleSwitchHelper(JCTree swtch, JCExpression selector, List<JCCase> cases,
1361                       boolean patternSwitch) {
1362         int limit = code.nextreg;
1363         Assert.check(!selector.type.hasTag(CLASS));
1364         int switchStart = patternSwitch ? code.entryPoint() : -1;
1365         int startpcCrt = genCrt ? code.curCP() : 0;
1366         Assert.check(code.isStatementStart());
1367         Item sel = genExpr(selector, syms.intType);
1368         if (cases.isEmpty()) {
1369             // We are seeing:  switch <sel> {}
1370             sel.load().drop();
1371             if (genCrt)
1372                 code.crt.put(TreeInfo.skipParens(selector),
1373                              CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1374         } else {
1375             // We are seeing a nonempty switch.
1376             sel.load();
1377             if (genCrt)
1378                 code.crt.put(TreeInfo.skipParens(selector),
1379                              CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1380             Env<GenContext> switchEnv = env.dup(swtch, new GenContext());
1381             switchEnv.info.isSwitch = true;

1590             @Override
1591             void afterBody() {
1592                 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) {
1593                     //for body-only finally, remove the GenFinalizer after try body
1594                     //so that the finally is not generated to catch bodies:
1595                     tryEnv.info.finalize = null;
1596                 }
1597             }
1598 
1599         };
1600         tryEnv.info.gaps = new ListBuffer<>();
1601         genTry(tree.body, tree.catchers, tryEnv);
1602     }
1603     //where
1604         /** Generate code for a try or synchronized statement
1605          *  @param body      The body of the try or synchronized statement.
1606          *  @param catchers  The list of catch clauses.
1607          *  @param env       The current environment of the body.
1608          */
1609         void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1610             genTryHelper(body, catchers, env);
1611         }
1612 
1613         void genTryHelper(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1614             int limit = code.nextreg;
1615             int startpc = code.curCP();
1616             Code.State stateTry = code.state.dup();
1617             genStat(body, env, CRT_BLOCK);
1618             int endpc = code.curCP();
1619             List<Integer> gaps = env.info.gaps.toList();
1620             code.statBegin(TreeInfo.endPos(body));
1621             genFinalizer(env);
1622             code.statBegin(TreeInfo.endPos(env.tree));
1623             Chain exitChain;
1624             boolean actualTry = env.tree.hasTag(TRY);
1625             if (startpc == endpc && actualTry) {
1626                 exitChain = code.branch(dontgoto);
1627             } else {
1628                 exitChain = code.branch(goto_);
1629             }
1630             endFinalizerGap(env);
1631             env.info.finalize.afterBody();
1632             boolean hasFinalizer =
1633                 env.info.finalize != null &&

1805         /** Register a catch clause in the "Exceptions" code-attribute.
1806          */
1807         void registerCatch(DiagnosticPosition pos,
1808                            int startpc, int endpc,
1809                            int handler_pc, int catch_type) {
1810             char startpc1 = (char)startpc;
1811             char endpc1 = (char)endpc;
1812             char handler_pc1 = (char)handler_pc;
1813             if (startpc1 == startpc &&
1814                 endpc1 == endpc &&
1815                 handler_pc1 == handler_pc) {
1816                 code.addCatch(startpc1, endpc1, handler_pc1,
1817                               (char)catch_type);
1818             } else {
1819                 log.error(pos, Errors.LimitCodeTooLargeForTryStmt);
1820                 nerrs++;
1821             }
1822         }
1823 
1824     public void visitIf(JCIf tree) {
1825         visitIfHelper(tree);
1826     }
1827 
1828     public void visitIfHelper(JCIf tree) {
1829         int limit = code.nextreg;
1830         Chain thenExit = null;
1831         Assert.check(code.isStatementStart());
1832         CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1833                              CRT_FLOW_CONTROLLER);
1834         Chain elseChain = c.jumpFalse();
1835         Assert.check(code.isStatementStart());
1836         if (!c.isFalse()) {
1837             code.resolve(c.trueJumps);
1838             genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1839             thenExit = code.branch(goto_);
1840         }
1841         if (elseChain != null) {
1842             code.resolve(elseChain);
1843             if (tree.elsepart != null) {
1844                 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
1845             }
1846         }
1847         code.resolve(thenExit);
1848         code.endScopes(limit);

2529     }
2530 
2531 /* ************************************************************************
2532  * main method
2533  *************************************************************************/
2534 
2535     /** Generate code for a class definition.
2536      *  @param env   The attribution environment that belongs to the
2537      *               outermost class containing this class definition.
2538      *               We need this for resolving some additional symbols.
2539      *  @param cdef  The tree representing the class definition.
2540      *  @return      True if code is generated with no errors.
2541      */
2542     public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2543         try {
2544             attrEnv = env;
2545             ClassSymbol c = cdef.sym;
2546             this.toplevel = env.toplevel;
2547             /* method normalizeDefs() can add references to external classes into the constant pool
2548              */
2549             cdef.defs = normalizeDefs(cdef);
2550             generateReferencesToPrunedTree(c);
2551             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2552             localEnv.toplevel = env.toplevel;
2553             localEnv.enclClass = cdef;
2554 
2555             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2556                 genDef(l.head, localEnv);
2557             }
2558             if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2559                 log.error(cdef.pos(), Errors.LimitPool);
2560                 nerrs++;
2561             }
2562             if (nerrs != 0) {
2563                 // if errors, discard code
2564                 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2565                     if (l.head.hasTag(METHODDEF))
2566                         ((JCMethodDecl) l.head).sym.code = null;
2567                 }
2568             }
2569             cdef.defs = List.nil(); // discard trees
< prev index next >