< 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

1012                 code.compressCatchTable();
1013 
1014                 // Fill in type annotation positions for exception parameters
1015                 code.fillExceptionParameterPositions();
1016             }
1017         }
1018 
1019         private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1020             MethodSymbol meth = tree.sym;
1021 
1022             // Create a new code structure.
1023             meth.code = code = new Code(meth,
1024                                         fatcode,
1025                                         lineDebugInfo ? toplevel.lineMap : null,
1026                                         varDebugInfo,
1027                                         stackMap,
1028                                         debugCode,
1029                                         genCrt ? new CRTable(tree) : null,
1030                                         syms,
1031                                         types,
1032                                         poolWriter);

1033             items = new Items(poolWriter, code, syms, types);
1034             if (code.debugCode) {
1035                 System.err.println(meth + " for body " + tree);
1036             }
1037 
1038             // If method is not static, create a new local variable address
1039             // for `this'.
1040             if ((tree.mods.flags & STATIC) == 0) {
1041                 Type selfType = meth.owner.type;
1042                 if (meth.isConstructor() && selfType != syms.objectType)
1043                     selfType = UninitializedType.uninitializedThis(selfType);
1044                 code.setDefined(
1045                         code.newLocal(
1046                             new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1047             }
1048 
1049             // Mark all parameters as defined from the beginning of
1050             // the method.
1051             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1052                 checkDimension(l.head.pos(), l.head.sym.type);
1053                 code.setDefined(code.newLocal(l.head.sym));
1054             }
1055 




1056             // Get ready to generate code for method body.
1057             int startpcCrt = genCrt ? code.curCP() : 0;
1058             code.entryPoint();
1059 
1060             // Suppress initial stackmap
1061             code.pendingStackMap = false;
1062 
1063             return startpcCrt;
1064         }
1065 
1066     public void visitVarDef(JCVariableDecl tree) {
1067         VarSymbol v = tree.sym;
1068         if (tree.init != null) {
1069             checkStringConstant(tree.init.pos(), v.getConstValue());
1070             if (v.getConstValue() == null || varDebugInfo) {
1071                 Assert.check(code.isStatementStart());
1072                 code.newLocal(v);
1073                 genExpr(tree.init, v.erasure(types)).load();
1074                 items.makeLocalItem(v).store();
1075                 Assert.check(code.isStatementStart());

1148     public void visitForLoop(JCForLoop tree) {
1149         int limit = code.nextreg;
1150         genStats(tree.init, env);
1151         genLoop(tree, tree.body, tree.cond, tree.step, true);
1152         code.endScopes(limit);
1153     }
1154     //where
1155         /** Generate code for a loop.
1156          *  @param loop       The tree representing the loop.
1157          *  @param body       The loop's body.
1158          *  @param cond       The loop's controlling condition.
1159          *  @param step       "Step" statements to be inserted at end of
1160          *                    each iteration.
1161          *  @param testFirst  True if the loop test belongs before the body.
1162          */
1163         private void genLoop(JCStatement loop,
1164                              JCStatement body,
1165                              JCExpression cond,
1166                              List<JCExpressionStatement> step,
1167                              boolean testFirst) {








1168             Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1169             int startpc = code.entryPoint();
1170             if (testFirst) { //while or for loop
1171                 CondItem c;
1172                 if (cond != null) {
1173                     code.statBegin(cond.pos);
1174                     Assert.check(code.isStatementStart());
1175                     c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1176                 } else {
1177                     c = items.makeCondItem(goto_);
1178                 }
1179                 Chain loopDone = c.jumpFalse();
1180                 code.resolve(c.trueJumps);
1181                 Assert.check(code.isStatementStart());
1182                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1183                 code.resolve(loopEnv.info.cont);
1184                 genStats(step, loopEnv);
1185                 code.resolve(code.branch(goto_), startpc);
1186                 code.resolve(loopDone);
1187             } else {

1286                     hasTry = true;
1287                 }
1288 
1289                 @Override
1290                 public void visitClassDef(JCClassDecl tree) {
1291                 }
1292 
1293                 @Override
1294                 public void visitLambda(JCLambda tree) {
1295                 }
1296             };
1297 
1298             HasTryScanner hasTryScanner = new HasTryScanner();
1299 
1300             hasTryScanner.scan(tree);
1301             return hasTryScanner.hasTry;
1302         }
1303 
1304     private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases,
1305                               boolean patternSwitch) {





1306         int limit = code.nextreg;
1307         Assert.check(!selector.type.hasTag(CLASS));
1308         int switchStart = patternSwitch ? code.entryPoint() : -1;
1309         int startpcCrt = genCrt ? code.curCP() : 0;
1310         Assert.check(code.isStatementStart());
1311         Item sel = genExpr(selector, syms.intType);
1312         if (cases.isEmpty()) {
1313             // We are seeing:  switch <sel> {}
1314             sel.load().drop();
1315             if (genCrt)
1316                 code.crt.put(TreeInfo.skipParens(selector),
1317                              CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1318         } else {
1319             // We are seeing a nonempty switch.
1320             sel.load();
1321             if (genCrt)
1322                 code.crt.put(TreeInfo.skipParens(selector),
1323                              CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1324             Env<GenContext> switchEnv = env.dup(swtch, new GenContext());
1325             switchEnv.info.isSwitch = true;

1534             @Override
1535             void afterBody() {
1536                 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) {
1537                     //for body-only finally, remove the GenFinalizer after try body
1538                     //so that the finally is not generated to catch bodies:
1539                     tryEnv.info.finalize = null;
1540                 }
1541             }
1542 
1543         };
1544         tryEnv.info.gaps = new ListBuffer<>();
1545         genTry(tree.body, tree.catchers, tryEnv);
1546     }
1547     //where
1548         /** Generate code for a try or synchronized statement
1549          *  @param body      The body of the try or synchronized statement.
1550          *  @param catchers  The list of catch clauses.
1551          *  @param env       The current environment of the body.
1552          */
1553         void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {




1554             int limit = code.nextreg;
1555             int startpc = code.curCP();
1556             Code.State stateTry = code.state.dup();
1557             genStat(body, env, CRT_BLOCK);
1558             int endpc = code.curCP();
1559             List<Integer> gaps = env.info.gaps.toList();
1560             code.statBegin(TreeInfo.endPos(body));
1561             genFinalizer(env);
1562             code.statBegin(TreeInfo.endPos(env.tree));
1563             Chain exitChain;
1564             boolean actualTry = env.tree.hasTag(TRY);
1565             if (startpc == endpc && actualTry) {
1566                 exitChain = code.branch(dontgoto);
1567             } else {
1568                 exitChain = code.branch(goto_);
1569             }
1570             endFinalizerGap(env);
1571             env.info.finalize.afterBody();
1572             boolean hasFinalizer =
1573                 env.info.finalize != null &&

1745         /** Register a catch clause in the "Exceptions" code-attribute.
1746          */
1747         void registerCatch(DiagnosticPosition pos,
1748                            int startpc, int endpc,
1749                            int handler_pc, int catch_type) {
1750             char startpc1 = (char)startpc;
1751             char endpc1 = (char)endpc;
1752             char handler_pc1 = (char)handler_pc;
1753             if (startpc1 == startpc &&
1754                 endpc1 == endpc &&
1755                 handler_pc1 == handler_pc) {
1756                 code.addCatch(startpc1, endpc1, handler_pc1,
1757                               (char)catch_type);
1758             } else {
1759                 log.error(pos, Errors.LimitCodeTooLargeForTryStmt);
1760                 nerrs++;
1761             }
1762         }
1763 
1764     public void visitIf(JCIf tree) {




1765         int limit = code.nextreg;
1766         Chain thenExit = null;
1767         Assert.check(code.isStatementStart());
1768         CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1769                              CRT_FLOW_CONTROLLER);
1770         Chain elseChain = c.jumpFalse();
1771         Assert.check(code.isStatementStart());
1772         if (!c.isFalse()) {
1773             code.resolve(c.trueJumps);
1774             genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1775             thenExit = code.branch(goto_);
1776         }
1777         if (elseChain != null) {
1778             code.resolve(elseChain);
1779             if (tree.elsepart != null) {
1780                 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
1781             }
1782         }
1783         code.resolve(thenExit);
1784         code.endScopes(limit);

2465     }
2466 
2467 /* ************************************************************************
2468  * main method
2469  *************************************************************************/
2470 
2471     /** Generate code for a class definition.
2472      *  @param env   The attribution environment that belongs to the
2473      *               outermost class containing this class definition.
2474      *               We need this for resolving some additional symbols.
2475      *  @param cdef  The tree representing the class definition.
2476      *  @return      True if code is generated with no errors.
2477      */
2478     public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2479         try {
2480             attrEnv = env;
2481             ClassSymbol c = cdef.sym;
2482             this.toplevel = env.toplevel;
2483             /* method normalizeDefs() can add references to external classes into the constant pool
2484              */
2485             cdef.defs = normalizeDefs(cdef.defs, c);
2486             generateReferencesToPrunedTree(c);
2487             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2488             localEnv.toplevel = env.toplevel;
2489             localEnv.enclClass = cdef;
2490 
2491             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2492                 genDef(l.head, localEnv);
2493             }
2494             if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2495                 log.error(cdef.pos(), Errors.LimitPool);
2496                 nerrs++;
2497             }
2498             if (nerrs != 0) {
2499                 // if errors, discard code
2500                 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2501                     if (l.head.hasTag(METHODDEF))
2502                         ((JCMethodDecl) l.head).sym.code = null;
2503                 }
2504             }
2505             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

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

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

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

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

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

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