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
|