60 * <p><b>This is NOT part of any supported API.
61 * If you write code that depends on this, you do so at your own risk.
62 * This code and its internal interfaces are subject to change or
63 * deletion without notice.</b>
64 */
65 public class Gen extends JCTree.Visitor {
66 protected static final Context.Key<Gen> genKey = new Context.Key<>();
67
68 private final Log log;
69 private final Symtab syms;
70 private final Check chk;
71 private final Resolve rs;
72 private final TreeMaker make;
73 private final Names names;
74 private final Target target;
75 private final String accessDollar;
76 private final Types types;
77 private final Lower lower;
78 private final Annotate annotate;
79 private final StringConcat concat;
80
81 /** Format of stackmap tables to be generated. */
82 private final Code.StackMapFormat stackMap;
83
84 /** A type that serves as the expected type for all method expressions.
85 */
86 private final Type methodType;
87
88 public static Gen instance(Context context) {
89 Gen instance = context.get(genKey);
90 if (instance == null)
91 instance = new Gen(context);
92 return instance;
93 }
94
95 /** Constant pool writer, set by genClass.
96 */
97 final PoolWriter poolWriter;
98
99 @SuppressWarnings("this-escape")
100 protected Gen(Context context) {
101 context.put(genKey, this);
102
103 names = Names.instance(context);
104 log = Log.instance(context);
105 syms = Symtab.instance(context);
106 chk = Check.instance(context);
107 rs = Resolve.instance(context);
108 make = TreeMaker.instance(context);
109 target = Target.instance(context);
110 types = Types.instance(context);
111 concat = StringConcat.instance(context);
112
113 methodType = new MethodType(null, null, null, syms.methodClass);
114 accessDollar = "access" + target.syntheticNameChar();
115 lower = Lower.instance(context);
116
117 Options options = Options.instance(context);
118 lineDebugInfo =
119 options.isUnset(G_CUSTOM) ||
120 options.isSet(G_CUSTOM, "lines");
121 varDebugInfo =
122 options.isUnset(G_CUSTOM)
123 ? options.isSet(G)
124 : options.isSet(G_CUSTOM, "vars");
125 genCrt = options.isSet(XJCOV);
126 debugCode = options.isSet("debug.code");
127 disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
128 poolWriter = new PoolWriter(types, names);
129
130 // ignore cldc because we cannot have both stackmap formats
131 this.stackMap = StackMapFormat.JSR202;
132 annotate = Annotate.instance(context);
133 qualifiedSymbolCache = new HashMap<>();
134 }
135
136 /** Switches
137 */
138 private final boolean lineDebugInfo;
139 private final boolean varDebugInfo;
140 private final boolean genCrt;
141 private final boolean debugCode;
142 private boolean disableVirtualizedPrivateInvoke;
143
144 /** Code buffer, set by genMethod.
145 */
146 private Code code;
147
148 /** Items structure, set by genMethod.
149 */
150 private Items items;
151
152 /** Environment for symbol lookup, set by genClass
153 */
154 private Env<AttrContext> attrEnv;
155
156 /** The top level tree.
157 */
158 private JCCompilationUnit toplevel;
159
160 /** The number of code-gen errors in this class.
161 */
162 private int nerrs = 0;
396 /** Do any of the structures aborted by a non-local exit have
397 * finalizers that require an empty stack?
398 * @param target The tree representing the structure that's aborted
399 * @param env The environment current at the non-local exit.
400 */
401 boolean hasFinally(JCTree target, Env<GenContext> env) {
402 while (env.tree != target) {
403 if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer())
404 return true;
405 env = env.next;
406 }
407 return false;
408 }
409
410 /* ************************************************************************
411 * Normalizing class-members.
412 *************************************************************************/
413
414 /** Distribute member initializer code into constructors and {@code <clinit>}
415 * method.
416 * @param defs The list of class member declarations.
417 * @param c The enclosing class.
418 */
419 List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) {
420 ListBuffer<JCStatement> initCode = new ListBuffer<>();
421 ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>();
422 ListBuffer<JCStatement> clinitCode = new ListBuffer<>();
423 ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>();
424 ListBuffer<JCTree> methodDefs = new ListBuffer<>();
425 // Sort definitions into three listbuffers:
426 // - initCode for instance initializers
427 // - clinitCode for class initializers
428 // - methodDefs for method definitions
429 for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) {
430 JCTree def = l.head;
431 switch (def.getTag()) {
432 case BLOCK:
433 JCBlock block = (JCBlock)def;
434 if ((block.flags & STATIC) != 0)
435 clinitCode.append(block);
436 else if ((block.flags & SYNTHETIC) == 0)
437 initCode.append(block);
438 break;
439 case METHODDEF:
440 methodDefs.append(def);
441 break;
442 case VARDEF:
443 JCVariableDecl vdef = (JCVariableDecl) def;
444 VarSymbol sym = vdef.sym;
445 checkDimension(vdef.pos(), sym.type);
446 if (vdef.init != null) {
447 if ((sym.flags() & STATIC) == 0) {
448 // Always initialize instance variables.
449 JCStatement init = make.at(vdef.pos()).
450 Assignment(sym, vdef.init);
451 initCode.append(init);
452 init.endpos = vdef.endpos;
453 initTAs.addAll(getAndRemoveNonFieldTAs(sym));
454 } else if (sym.getConstValue() == null) {
455 // Initialize class (static) variables only if
456 // they are not compile-time constants.
457 JCStatement init = make.at(vdef.pos).
458 Assignment(sym, vdef.init);
459 clinitCode.append(init);
460 init.endpos = vdef.endpos;
461 clinitTAs.addAll(getAndRemoveNonFieldTAs(sym));
462 } else {
463 checkStringConstant(vdef.init.pos(), sym.getConstValue());
464 /* if the init contains a reference to an external class, add it to the
465 * constant's pool
466 */
467 vdef.init.accept(classReferenceVisitor);
468 }
469 }
470 break;
471 default:
472 Assert.error();
473 }
474 }
475 // Insert any instance initializers into all constructors.
476 if (initCode.length() != 0) {
477 List<JCStatement> inits = initCode.toList();
478 initTAs.addAll(c.getInitTypeAttributes());
479 List<Attribute.TypeCompound> initTAlist = initTAs.toList();
480 for (JCTree t : methodDefs) {
481 normalizeMethod((JCMethodDecl)t, inits, initTAlist);
482 }
483 }
484 // If there are class initializers, create a <clinit> method
485 // that contains them as its body.
486 if (clinitCode.length() != 0) {
487 MethodSymbol clinit = new MethodSymbol(
488 STATIC | (c.flags() & STRICTFP),
489 names.clinit,
490 new MethodType(
491 List.nil(), syms.voidType,
492 List.nil(), syms.methodClass),
493 c);
494 c.members().enter(clinit);
495 List<JCStatement> clinitStats = clinitCode.toList();
496 JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
497 block.bracePos = TreeInfo.endPos(clinitStats.last());
498 methodDefs.append(make.MethodDef(clinit, block));
499
500 if (!clinitTAs.isEmpty())
501 clinit.appendUniqueTypeAttributes(clinitTAs.toList());
502 if (!c.getClassInitTypeAttributes().isEmpty())
503 clinit.appendUniqueTypeAttributes(c.getClassInitTypeAttributes());
504 }
505 // Return all method definitions.
506 return methodDefs.toList();
507 }
508
509 private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) {
510 List<TypeCompound> tas = sym.getRawTypeAttributes();
511 ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>();
512 ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>();
513 for (TypeCompound ta : tas) {
514 Assert.check(ta.getPosition().type != TargetType.UNKNOWN);
515 if (ta.getPosition().type == TargetType.FIELD) {
516 fieldTAs.add(ta);
517 } else {
518 nonfieldTAs.add(ta);
519 }
520 }
521 sym.setTypeAttributes(fieldTAs.toList());
522 return nonfieldTAs.toList();
523 }
524
525 /** Check a constant value and report if it is a string that is
526 * too large.
527 */
528 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
529 if (nerrs != 0 || // only complain about a long string once
530 constValue == null ||
531 !(constValue instanceof String str) ||
532 str.length() < PoolWriter.MAX_STRING_LENGTH)
533 return;
534 log.error(pos, Errors.LimitString);
535 nerrs++;
536 }
537
538 /** Insert instance initializer code into constructors prior to the super() call.
539 * @param md The tree potentially representing a
540 * constructor's definition.
541 * @param initCode The list of instance initializer statements.
542 * @param initTAs Type annotations from the initializer expression.
543 */
544 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
545 if (TreeInfo.isConstructor(md) && TreeInfo.hasConstructorCall(md, names._super)) {
546 // We are seeing a constructor that has a super() call.
547 // Find the super() invocation and append the given initializer code.
548 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall)));
549
550 if (md.body.bracePos == Position.NOPOS)
551 md.body.bracePos = TreeInfo.endPos(md.body.stats.last());
552
553 md.sym.appendUniqueTypeAttributes(initTAs);
554 }
555 }
556
557 /* ************************************************************************
558 * Traversal methods
559 *************************************************************************/
560
561 /** Visitor argument: The current environment.
562 */
563 Env<GenContext> env;
564
565 /** Visitor argument: The expected type (prototype).
566 */
567 Type pt;
568
569 /** Visitor result: The item representing the computed value.
570 */
571 Item result;
572
573 /** Visitor method: generate code for a definition, catching and reporting
999 code.compressCatchTable();
1000
1001 // Fill in type annotation positions for exception parameters
1002 code.fillExceptionParameterPositions();
1003 }
1004 }
1005
1006 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1007 MethodSymbol meth = tree.sym;
1008
1009 // Create a new code structure.
1010 meth.code = code = new Code(meth,
1011 fatcode,
1012 lineDebugInfo ? toplevel.lineMap : null,
1013 varDebugInfo,
1014 stackMap,
1015 debugCode,
1016 genCrt ? new CRTable(tree) : null,
1017 syms,
1018 types,
1019 poolWriter);
1020 items = new Items(poolWriter, code, syms, types);
1021 if (code.debugCode) {
1022 System.err.println(meth + " for body " + tree);
1023 }
1024
1025 // If method is not static, create a new local variable address
1026 // for `this'.
1027 if ((tree.mods.flags & STATIC) == 0) {
1028 Type selfType = meth.owner.type;
1029 if (meth.isConstructor() && selfType != syms.objectType)
1030 selfType = UninitializedType.uninitializedThis(selfType);
1031 code.setDefined(
1032 code.newLocal(
1033 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1034 }
1035
1036 // Mark all parameters as defined from the beginning of
1037 // the method.
1038 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1039 checkDimension(l.head.pos(), l.head.sym.type);
1040 code.setDefined(code.newLocal(l.head.sym));
1041 }
1042
1043 // Get ready to generate code for method body.
1044 int startpcCrt = genCrt ? code.curCP() : 0;
1045 code.entryPoint();
1046
1047 // Suppress initial stackmap
1048 code.pendingStackMap = false;
1049
1050 return startpcCrt;
1051 }
1052
1053 public void visitVarDef(JCVariableDecl tree) {
1054 VarSymbol v = tree.sym;
1055 if (tree.init != null) {
1056 checkStringConstant(tree.init.pos(), v.getConstValue());
1057 if (v.getConstValue() == null || varDebugInfo) {
1058 Assert.check(code.isStatementStart());
1059 code.newLocal(v);
1060 genExpr(tree.init, v.erasure(types)).load();
1061 items.makeLocalItem(v).store();
1062 Assert.check(code.isStatementStart());
1135 public void visitForLoop(JCForLoop tree) {
1136 int limit = code.nextreg;
1137 genStats(tree.init, env);
1138 genLoop(tree, tree.body, tree.cond, tree.step, true);
1139 code.endScopes(limit);
1140 }
1141 //where
1142 /** Generate code for a loop.
1143 * @param loop The tree representing the loop.
1144 * @param body The loop's body.
1145 * @param cond The loop's controlling condition.
1146 * @param step "Step" statements to be inserted at end of
1147 * each iteration.
1148 * @param testFirst True if the loop test belongs before the body.
1149 */
1150 private void genLoop(JCStatement loop,
1151 JCStatement body,
1152 JCExpression cond,
1153 List<JCExpressionStatement> step,
1154 boolean testFirst) {
1155 Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1156 int startpc = code.entryPoint();
1157 if (testFirst) { //while or for loop
1158 CondItem c;
1159 if (cond != null) {
1160 code.statBegin(cond.pos);
1161 Assert.check(code.isStatementStart());
1162 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1163 } else {
1164 c = items.makeCondItem(goto_);
1165 }
1166 Chain loopDone = c.jumpFalse();
1167 code.resolve(c.trueJumps);
1168 Assert.check(code.isStatementStart());
1169 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1170 code.resolve(loopEnv.info.cont);
1171 genStats(step, loopEnv);
1172 code.resolve(code.branch(goto_), startpc);
1173 code.resolve(loopDone);
1174 } else {
1273 hasTry = true;
1274 }
1275
1276 @Override
1277 public void visitClassDef(JCClassDecl tree) {
1278 }
1279
1280 @Override
1281 public void visitLambda(JCLambda tree) {
1282 }
1283 };
1284
1285 HasTryScanner hasTryScanner = new HasTryScanner();
1286
1287 hasTryScanner.scan(tree);
1288 return hasTryScanner.hasTry;
1289 }
1290
1291 private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases,
1292 boolean patternSwitch) {
1293 int limit = code.nextreg;
1294 Assert.check(!selector.type.hasTag(CLASS));
1295 int switchStart = patternSwitch ? code.entryPoint() : -1;
1296 int startpcCrt = genCrt ? code.curCP() : 0;
1297 Assert.check(code.isStatementStart());
1298 Item sel = genExpr(selector, syms.intType);
1299 if (cases.isEmpty()) {
1300 // We are seeing: switch <sel> {}
1301 sel.load().drop();
1302 if (genCrt)
1303 code.crt.put(TreeInfo.skipParens(selector),
1304 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1305 } else {
1306 // We are seeing a nonempty switch.
1307 sel.load();
1308 if (genCrt)
1309 code.crt.put(TreeInfo.skipParens(selector),
1310 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1311 Env<GenContext> switchEnv = env.dup(swtch, new GenContext());
1312 switchEnv.info.isSwitch = true;
1521 @Override
1522 void afterBody() {
1523 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) {
1524 //for body-only finally, remove the GenFinalizer after try body
1525 //so that the finally is not generated to catch bodies:
1526 tryEnv.info.finalize = null;
1527 }
1528 }
1529
1530 };
1531 tryEnv.info.gaps = new ListBuffer<>();
1532 genTry(tree.body, tree.catchers, tryEnv);
1533 }
1534 //where
1535 /** Generate code for a try or synchronized statement
1536 * @param body The body of the try or synchronized statement.
1537 * @param catchers The list of catch clauses.
1538 * @param env The current environment of the body.
1539 */
1540 void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1541 int limit = code.nextreg;
1542 int startpc = code.curCP();
1543 Code.State stateTry = code.state.dup();
1544 genStat(body, env, CRT_BLOCK);
1545 int endpc = code.curCP();
1546 List<Integer> gaps = env.info.gaps.toList();
1547 code.statBegin(TreeInfo.endPos(body));
1548 genFinalizer(env);
1549 code.statBegin(TreeInfo.endPos(env.tree));
1550 Chain exitChain;
1551 boolean actualTry = env.tree.hasTag(TRY);
1552 if (startpc == endpc && actualTry) {
1553 exitChain = code.branch(dontgoto);
1554 } else {
1555 exitChain = code.branch(goto_);
1556 }
1557 endFinalizerGap(env);
1558 env.info.finalize.afterBody();
1559 boolean hasFinalizer =
1560 env.info.finalize != null &&
1732 /** Register a catch clause in the "Exceptions" code-attribute.
1733 */
1734 void registerCatch(DiagnosticPosition pos,
1735 int startpc, int endpc,
1736 int handler_pc, int catch_type) {
1737 char startpc1 = (char)startpc;
1738 char endpc1 = (char)endpc;
1739 char handler_pc1 = (char)handler_pc;
1740 if (startpc1 == startpc &&
1741 endpc1 == endpc &&
1742 handler_pc1 == handler_pc) {
1743 code.addCatch(startpc1, endpc1, handler_pc1,
1744 (char)catch_type);
1745 } else {
1746 log.error(pos, Errors.LimitCodeTooLargeForTryStmt);
1747 nerrs++;
1748 }
1749 }
1750
1751 public void visitIf(JCIf tree) {
1752 int limit = code.nextreg;
1753 Chain thenExit = null;
1754 Assert.check(code.isStatementStart());
1755 CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1756 CRT_FLOW_CONTROLLER);
1757 Chain elseChain = c.jumpFalse();
1758 Assert.check(code.isStatementStart());
1759 if (!c.isFalse()) {
1760 code.resolve(c.trueJumps);
1761 genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1762 thenExit = code.branch(goto_);
1763 }
1764 if (elseChain != null) {
1765 code.resolve(elseChain);
1766 if (tree.elsepart != null) {
1767 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
1768 }
1769 }
1770 code.resolve(thenExit);
1771 code.endScopes(limit);
2452 }
2453
2454 /* ************************************************************************
2455 * main method
2456 *************************************************************************/
2457
2458 /** Generate code for a class definition.
2459 * @param env The attribution environment that belongs to the
2460 * outermost class containing this class definition.
2461 * We need this for resolving some additional symbols.
2462 * @param cdef The tree representing the class definition.
2463 * @return True if code is generated with no errors.
2464 */
2465 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2466 try {
2467 attrEnv = env;
2468 ClassSymbol c = cdef.sym;
2469 this.toplevel = env.toplevel;
2470 /* method normalizeDefs() can add references to external classes into the constant pool
2471 */
2472 cdef.defs = normalizeDefs(cdef.defs, c);
2473 generateReferencesToPrunedTree(c);
2474 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2475 localEnv.toplevel = env.toplevel;
2476 localEnv.enclClass = cdef;
2477
2478 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2479 genDef(l.head, localEnv);
2480 }
2481 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2482 log.error(cdef.pos(), Errors.LimitPool);
2483 nerrs++;
2484 }
2485 if (nerrs != 0) {
2486 // if errors, discard code
2487 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2488 if (l.head.hasTag(METHODDEF))
2489 ((JCMethodDecl) l.head).sym.code = null;
2490 }
2491 }
2492 cdef.defs = List.nil(); // discard trees
|
60 * <p><b>This is NOT part of any supported API.
61 * If you write code that depends on this, you do so at your own risk.
62 * This code and its internal interfaces are subject to change or
63 * deletion without notice.</b>
64 */
65 public class Gen extends JCTree.Visitor {
66 protected static final Context.Key<Gen> genKey = new Context.Key<>();
67
68 private final Log log;
69 private final Symtab syms;
70 private final Check chk;
71 private final Resolve rs;
72 private final TreeMaker make;
73 private final Names names;
74 private final Target target;
75 private final String accessDollar;
76 private final Types types;
77 private final Lower lower;
78 private final Annotate annotate;
79 private final StringConcat concat;
80 private final LocalProxyVarsGen localProxyVarsGen;
81
82 /** Format of stackmap tables to be generated. */
83 private final Code.StackMapFormat stackMap;
84
85 /** A type that serves as the expected type for all method expressions.
86 */
87 private final Type methodType;
88
89 public static Gen instance(Context context) {
90 Gen instance = context.get(genKey);
91 if (instance == null)
92 instance = new Gen(context);
93 return instance;
94 }
95
96 /** Constant pool writer, set by genClass.
97 */
98 final PoolWriter poolWriter;
99
100 @SuppressWarnings("this-escape")
101 protected Gen(Context context) {
102 context.put(genKey, this);
103
104 names = Names.instance(context);
105 log = Log.instance(context);
106 syms = Symtab.instance(context);
107 chk = Check.instance(context);
108 rs = Resolve.instance(context);
109 make = TreeMaker.instance(context);
110 target = Target.instance(context);
111 types = Types.instance(context);
112 concat = StringConcat.instance(context);
113 localProxyVarsGen = LocalProxyVarsGen.instance(context);
114
115 methodType = new MethodType(null, null, null, syms.methodClass);
116 accessDollar = "access" + target.syntheticNameChar();
117 lower = Lower.instance(context);
118
119 Options options = Options.instance(context);
120 lineDebugInfo =
121 options.isUnset(G_CUSTOM) ||
122 options.isSet(G_CUSTOM, "lines");
123 varDebugInfo =
124 options.isUnset(G_CUSTOM)
125 ? options.isSet(G)
126 : options.isSet(G_CUSTOM, "vars");
127 genCrt = options.isSet(XJCOV);
128 debugCode = options.isSet("debug.code");
129 disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
130 poolWriter = new PoolWriter(types, names);
131
132 // ignore cldc because we cannot have both stackmap formats
133 this.stackMap = StackMapFormat.JSR202;
134 annotate = Annotate.instance(context);
135 qualifiedSymbolCache = new HashMap<>();
136 Preview preview = Preview.instance(context);
137 Source source = Source.instance(context);
138 allowValueClasses = preview.isEnabled() && Source.Feature.VALUE_CLASSES.allowedInSource(source);
139 }
140
141 /** Switches
142 */
143 private final boolean lineDebugInfo;
144 private final boolean varDebugInfo;
145 private final boolean genCrt;
146 private final boolean debugCode;
147 private boolean disableVirtualizedPrivateInvoke;
148 private final boolean allowValueClasses;
149
150 /** Code buffer, set by genMethod.
151 */
152 private Code code;
153
154 /** Items structure, set by genMethod.
155 */
156 private Items items;
157
158 /** Environment for symbol lookup, set by genClass
159 */
160 private Env<AttrContext> attrEnv;
161
162 /** The top level tree.
163 */
164 private JCCompilationUnit toplevel;
165
166 /** The number of code-gen errors in this class.
167 */
168 private int nerrs = 0;
402 /** Do any of the structures aborted by a non-local exit have
403 * finalizers that require an empty stack?
404 * @param target The tree representing the structure that's aborted
405 * @param env The environment current at the non-local exit.
406 */
407 boolean hasFinally(JCTree target, Env<GenContext> env) {
408 while (env.tree != target) {
409 if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer())
410 return true;
411 env = env.next;
412 }
413 return false;
414 }
415
416 /* ************************************************************************
417 * Normalizing class-members.
418 *************************************************************************/
419
420 /** Distribute member initializer code into constructors and {@code <clinit>}
421 * method.
422 * @param classDecl The class declaration to normalize.
423 */
424 List<JCTree> normalizeDefs(JCClassDecl classDecl) {
425 ListBuffer<JCStatement> initCode = new ListBuffer<>();
426 // only used for value classes
427 ListBuffer<JCStatement> initBlocks = new ListBuffer<>();
428 ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>();
429 ListBuffer<JCStatement> clinitCode = new ListBuffer<>();
430 ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>();
431 ListBuffer<JCTree> methodDefs = new ListBuffer<>();
432 // Sort definitions into three listbuffers:
433 // - initCode for instance initializers
434 // - clinitCode for class initializers
435 // - methodDefs for method definitions
436 for (List<JCTree> l = classDecl.defs; l.nonEmpty(); l = l.tail) {
437 JCTree def = l.head;
438 switch (def.getTag()) {
439 case BLOCK:
440 JCBlock block = (JCBlock)def;
441 if ((block.flags & STATIC) != 0)
442 clinitCode.append(block);
443 else if ((block.flags & SYNTHETIC) == 0) {
444 if (classDecl.sym.isValueClass()) {
445 initBlocks.append(block);
446 } else {
447 initCode.append(block);
448 }
449 }
450 break;
451 case METHODDEF:
452 methodDefs.append(def);
453 break;
454 case VARDEF:
455 JCVariableDecl vdef = (JCVariableDecl) def;
456 VarSymbol sym = vdef.sym;
457 checkDimension(vdef.pos(), sym.type);
458 if (vdef.init != null) {
459 if ((sym.flags() & STATIC) == 0) {
460 // Always initialize instance variables.
461 JCStatement init = make.at(vdef.pos()).
462 Assignment(sym, vdef.init);
463 initCode.append(init);
464 init.endpos = vdef.endpos;
465 initTAs.addAll(getAndRemoveNonFieldTAs(sym));
466 } else if (sym.getConstValue() == null) {
467 // Initialize class (static) variables only if
468 // they are not compile-time constants.
469 JCStatement init = make.at(vdef.pos).
470 Assignment(sym, vdef.init);
471 clinitCode.append(init);
472 init.endpos = vdef.endpos;
473 clinitTAs.addAll(getAndRemoveNonFieldTAs(sym));
474 } else {
475 checkStringConstant(vdef.init.pos(), sym.getConstValue());
476 /* if the init contains a reference to an external class, add it to the
477 * constant's pool
478 */
479 vdef.init.accept(classReferenceVisitor);
480 }
481 }
482 break;
483 default:
484 Assert.error();
485 }
486 }
487 // Insert any instance initializers into all constructors.
488 List<TypeCompound> initTAlist = List.nil();
489 if (initCode.nonEmpty() || initBlocks.nonEmpty()) {
490 initTAs.addAll(classDecl.sym.getInitTypeAttributes());
491 initTAlist = initTAs.toList();
492 }
493 for (JCTree t : methodDefs) {
494 normalizeMethod((JCMethodDecl)t, initCode.toList(), initBlocks.toList(), initTAlist);
495 }
496 localProxyVarsGen.allFieldNormalized(classDecl.sym);
497 // If there are class initializers, create a <clinit> method
498 // that contains them as its body.
499 if (clinitCode.length() != 0) {
500 MethodSymbol clinit = new MethodSymbol(
501 STATIC | (classDecl.sym.flags() & STRICTFP),
502 names.clinit,
503 new MethodType(
504 List.nil(), syms.voidType,
505 List.nil(), syms.methodClass),
506 classDecl.sym);
507 classDecl.sym.members().enter(clinit);
508 List<JCStatement> clinitStats = clinitCode.toList();
509 JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
510 block.bracePos = TreeInfo.endPos(clinitStats.last());
511 methodDefs.append(make.MethodDef(clinit, block));
512
513 if (!clinitTAs.isEmpty())
514 clinit.appendUniqueTypeAttributes(clinitTAs.toList());
515 if (!classDecl.sym.getClassInitTypeAttributes().isEmpty())
516 clinit.appendUniqueTypeAttributes(classDecl.sym.getClassInitTypeAttributes());
517 }
518 // Return all method definitions.
519 return methodDefs.toList();
520 }
521
522 private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) {
523 List<TypeCompound> tas = sym.getRawTypeAttributes();
524 ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>();
525 ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>();
526 for (TypeCompound ta : tas) {
527 Assert.check(ta.getPosition().type != TargetType.UNKNOWN);
528 if (ta.getPosition().type == TargetType.FIELD) {
529 fieldTAs.add(ta);
530 } else {
531 nonfieldTAs.add(ta);
532 }
533 }
534 sym.setTypeAttributes(fieldTAs.toList());
535 return nonfieldTAs.toList();
536 }
537
538 /** Check a constant value and report if it is a string that is
539 * too large.
540 */
541 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
542 if (nerrs != 0 || // only complain about a long string once
543 constValue == null ||
544 !(constValue instanceof String str) ||
545 str.length() < PoolWriter.MAX_STRING_LENGTH)
546 return;
547 log.error(pos, Errors.LimitString);
548 nerrs++;
549 }
550
551 /** Insert instance initializer code into constructors prior to the super() call.
552 * @param md The tree potentially representing a
553 * constructor's definition.
554 * @param initCode The list of instance initializer statements.
555 * @param initTAs Type annotations from the initializer expression.
556 */
557 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<JCStatement> initBlocks, List<TypeCompound> initTAs) {
558 if (TreeInfo.isConstructor(md) && TreeInfo.hasConstructorCall(md, names._super)) {
559 // We are seeing a constructor that has a super() call.
560 // Find the super() invocation and append the given initializer code.
561 if (initCode.nonEmpty() || initBlocks.nonEmpty()) {
562 if (allowValueClasses &&
563 (md.sym.owner.isValueClass() || ((md.sym.owner.flags_field & RECORD) != 0))) {
564 rewriteEarlyInitializersIfNeeded(md, initCode);
565 md.body.stats = initCode.appendList(md.body.stats);
566 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initBlocks.prepend(supercall)));
567 } else {
568 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall)));
569 }
570 md.sym.appendUniqueTypeAttributes(initTAs);
571 }
572
573 localProxyVarsGen.patchConstructor(md, make);
574
575 if (md.body.bracePos == Position.NOPOS)
576 md.body.bracePos = TreeInfo.endPos(md.body.stats.last());
577 }
578 }
579
580 /**
581 * Some early field initializer might contain references to synthetic Lower symbols,
582 * such as 'this$0' or local var proxies. Since these are effectively "early reads",
583 * we need to replace such reference with a reference to the corresponding
584 * (synthetic) constructor parameter.
585 */
586 void rewriteEarlyInitializersIfNeeded(JCMethodDecl md, List<JCStatement> initCode) {
587 class EarlyInitializerVisitor extends TreeScanner {
588 @Override
589 public void visitIdent(JCIdent tree) {
590 if ((tree.sym.flags() & OUTER_THIS_FIELD) != 0) {
591 tree.sym = md.sym.extraParams.head;
592 } else if ((tree.sym.flags() & LOCAL_CAPTURE_FIELD) != 0) {
593 Symbol capturedSym = tree.sym.baseSymbol();
594 tree.sym = md.sym.capturedLocals.stream()
595 .filter(l -> l.baseSymbol() == capturedSym)
596 .findAny().orElseThrow();
597 }
598 }
599 }
600 if (md.sym.capturedLocals.nonEmpty() || md.sym.extraParams.nonEmpty()) {
601 EarlyInitializerVisitor initializerVisitor = new EarlyInitializerVisitor();
602 for (JCStatement init : initCode) {
603 initializerVisitor.scan(init);
604 }
605 }
606 }
607
608 /* ************************************************************************
609 * Traversal methods
610 *************************************************************************/
611
612 /** Visitor argument: The current environment.
613 */
614 Env<GenContext> env;
615
616 /** Visitor argument: The expected type (prototype).
617 */
618 Type pt;
619
620 /** Visitor result: The item representing the computed value.
621 */
622 Item result;
623
624 /** Visitor method: generate code for a definition, catching and reporting
1050 code.compressCatchTable();
1051
1052 // Fill in type annotation positions for exception parameters
1053 code.fillExceptionParameterPositions();
1054 }
1055 }
1056
1057 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1058 MethodSymbol meth = tree.sym;
1059
1060 // Create a new code structure.
1061 meth.code = code = new Code(meth,
1062 fatcode,
1063 lineDebugInfo ? toplevel.lineMap : null,
1064 varDebugInfo,
1065 stackMap,
1066 debugCode,
1067 genCrt ? new CRTable(tree) : null,
1068 syms,
1069 types,
1070 poolWriter,
1071 allowValueClasses);
1072 items = new Items(poolWriter, code, syms, types);
1073 if (code.debugCode) {
1074 System.err.println(meth + " for body " + tree);
1075 }
1076
1077 // If method is not static, create a new local variable address
1078 // for `this'.
1079 if ((tree.mods.flags & STATIC) == 0) {
1080 Type selfType = meth.owner.type;
1081 if (meth.isConstructor() && selfType != syms.objectType)
1082 selfType = UninitializedType.uninitializedThis(selfType);
1083 code.setDefined(
1084 code.newLocal(
1085 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1086 }
1087
1088 // Mark all parameters as defined from the beginning of
1089 // the method.
1090 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1091 checkDimension(l.head.pos(), l.head.sym.type);
1092 code.setDefined(code.newLocal(l.head.sym));
1093 }
1094
1095 if (allowValueClasses && meth.isConstructor()) {
1096 code.initUnsetStrictFields(env.enclClass.sym);
1097 }
1098
1099 // Get ready to generate code for method body.
1100 int startpcCrt = genCrt ? code.curCP() : 0;
1101 code.entryPoint();
1102
1103 // Suppress initial stackmap
1104 code.pendingStackMap = false;
1105
1106 return startpcCrt;
1107 }
1108
1109 public void visitVarDef(JCVariableDecl tree) {
1110 VarSymbol v = tree.sym;
1111 if (tree.init != null) {
1112 checkStringConstant(tree.init.pos(), v.getConstValue());
1113 if (v.getConstValue() == null || varDebugInfo) {
1114 Assert.check(code.isStatementStart());
1115 code.newLocal(v);
1116 genExpr(tree.init, v.erasure(types)).load();
1117 items.makeLocalItem(v).store();
1118 Assert.check(code.isStatementStart());
1191 public void visitForLoop(JCForLoop tree) {
1192 int limit = code.nextreg;
1193 genStats(tree.init, env);
1194 genLoop(tree, tree.body, tree.cond, tree.step, true);
1195 code.endScopes(limit);
1196 }
1197 //where
1198 /** Generate code for a loop.
1199 * @param loop The tree representing the loop.
1200 * @param body The loop's body.
1201 * @param cond The loop's controlling condition.
1202 * @param step "Step" statements to be inserted at end of
1203 * each iteration.
1204 * @param testFirst True if the loop test belongs before the body.
1205 */
1206 private void genLoop(JCStatement loop,
1207 JCStatement body,
1208 JCExpression cond,
1209 List<JCExpressionStatement> step,
1210 boolean testFirst) {
1211 genLoopHelper(loop, body, cond, step, testFirst);
1212 }
1213
1214 private void genLoopHelper(JCStatement loop,
1215 JCStatement body,
1216 JCExpression cond,
1217 List<JCExpressionStatement> step,
1218 boolean testFirst) {
1219 Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1220 int startpc = code.entryPoint();
1221 if (testFirst) { //while or for loop
1222 CondItem c;
1223 if (cond != null) {
1224 code.statBegin(cond.pos);
1225 Assert.check(code.isStatementStart());
1226 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1227 } else {
1228 c = items.makeCondItem(goto_);
1229 }
1230 Chain loopDone = c.jumpFalse();
1231 code.resolve(c.trueJumps);
1232 Assert.check(code.isStatementStart());
1233 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1234 code.resolve(loopEnv.info.cont);
1235 genStats(step, loopEnv);
1236 code.resolve(code.branch(goto_), startpc);
1237 code.resolve(loopDone);
1238 } else {
1337 hasTry = true;
1338 }
1339
1340 @Override
1341 public void visitClassDef(JCClassDecl tree) {
1342 }
1343
1344 @Override
1345 public void visitLambda(JCLambda tree) {
1346 }
1347 };
1348
1349 HasTryScanner hasTryScanner = new HasTryScanner();
1350
1351 hasTryScanner.scan(tree);
1352 return hasTryScanner.hasTry;
1353 }
1354
1355 private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases,
1356 boolean patternSwitch) {
1357 handleSwitchHelper(swtch, selector, cases, patternSwitch);
1358 }
1359
1360 void handleSwitchHelper(JCTree swtch, JCExpression selector, List<JCCase> cases,
1361 boolean patternSwitch) {
1362 int limit = code.nextreg;
1363 Assert.check(!selector.type.hasTag(CLASS));
1364 int switchStart = patternSwitch ? code.entryPoint() : -1;
1365 int startpcCrt = genCrt ? code.curCP() : 0;
1366 Assert.check(code.isStatementStart());
1367 Item sel = genExpr(selector, syms.intType);
1368 if (cases.isEmpty()) {
1369 // We are seeing: switch <sel> {}
1370 sel.load().drop();
1371 if (genCrt)
1372 code.crt.put(TreeInfo.skipParens(selector),
1373 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1374 } else {
1375 // We are seeing a nonempty switch.
1376 sel.load();
1377 if (genCrt)
1378 code.crt.put(TreeInfo.skipParens(selector),
1379 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1380 Env<GenContext> switchEnv = env.dup(swtch, new GenContext());
1381 switchEnv.info.isSwitch = true;
1590 @Override
1591 void afterBody() {
1592 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) {
1593 //for body-only finally, remove the GenFinalizer after try body
1594 //so that the finally is not generated to catch bodies:
1595 tryEnv.info.finalize = null;
1596 }
1597 }
1598
1599 };
1600 tryEnv.info.gaps = new ListBuffer<>();
1601 genTry(tree.body, tree.catchers, tryEnv);
1602 }
1603 //where
1604 /** Generate code for a try or synchronized statement
1605 * @param body The body of the try or synchronized statement.
1606 * @param catchers The list of catch clauses.
1607 * @param env The current environment of the body.
1608 */
1609 void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1610 genTryHelper(body, catchers, env);
1611 }
1612
1613 void genTryHelper(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1614 int limit = code.nextreg;
1615 int startpc = code.curCP();
1616 Code.State stateTry = code.state.dup();
1617 genStat(body, env, CRT_BLOCK);
1618 int endpc = code.curCP();
1619 List<Integer> gaps = env.info.gaps.toList();
1620 code.statBegin(TreeInfo.endPos(body));
1621 genFinalizer(env);
1622 code.statBegin(TreeInfo.endPos(env.tree));
1623 Chain exitChain;
1624 boolean actualTry = env.tree.hasTag(TRY);
1625 if (startpc == endpc && actualTry) {
1626 exitChain = code.branch(dontgoto);
1627 } else {
1628 exitChain = code.branch(goto_);
1629 }
1630 endFinalizerGap(env);
1631 env.info.finalize.afterBody();
1632 boolean hasFinalizer =
1633 env.info.finalize != null &&
1805 /** Register a catch clause in the "Exceptions" code-attribute.
1806 */
1807 void registerCatch(DiagnosticPosition pos,
1808 int startpc, int endpc,
1809 int handler_pc, int catch_type) {
1810 char startpc1 = (char)startpc;
1811 char endpc1 = (char)endpc;
1812 char handler_pc1 = (char)handler_pc;
1813 if (startpc1 == startpc &&
1814 endpc1 == endpc &&
1815 handler_pc1 == handler_pc) {
1816 code.addCatch(startpc1, endpc1, handler_pc1,
1817 (char)catch_type);
1818 } else {
1819 log.error(pos, Errors.LimitCodeTooLargeForTryStmt);
1820 nerrs++;
1821 }
1822 }
1823
1824 public void visitIf(JCIf tree) {
1825 visitIfHelper(tree);
1826 }
1827
1828 public void visitIfHelper(JCIf tree) {
1829 int limit = code.nextreg;
1830 Chain thenExit = null;
1831 Assert.check(code.isStatementStart());
1832 CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1833 CRT_FLOW_CONTROLLER);
1834 Chain elseChain = c.jumpFalse();
1835 Assert.check(code.isStatementStart());
1836 if (!c.isFalse()) {
1837 code.resolve(c.trueJumps);
1838 genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1839 thenExit = code.branch(goto_);
1840 }
1841 if (elseChain != null) {
1842 code.resolve(elseChain);
1843 if (tree.elsepart != null) {
1844 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
1845 }
1846 }
1847 code.resolve(thenExit);
1848 code.endScopes(limit);
2529 }
2530
2531 /* ************************************************************************
2532 * main method
2533 *************************************************************************/
2534
2535 /** Generate code for a class definition.
2536 * @param env The attribution environment that belongs to the
2537 * outermost class containing this class definition.
2538 * We need this for resolving some additional symbols.
2539 * @param cdef The tree representing the class definition.
2540 * @return True if code is generated with no errors.
2541 */
2542 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2543 try {
2544 attrEnv = env;
2545 ClassSymbol c = cdef.sym;
2546 this.toplevel = env.toplevel;
2547 /* method normalizeDefs() can add references to external classes into the constant pool
2548 */
2549 cdef.defs = normalizeDefs(cdef);
2550 generateReferencesToPrunedTree(c);
2551 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2552 localEnv.toplevel = env.toplevel;
2553 localEnv.enclClass = cdef;
2554
2555 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2556 genDef(l.head, localEnv);
2557 }
2558 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2559 log.error(cdef.pos(), Errors.LimitPool);
2560 nerrs++;
2561 }
2562 if (nerrs != 0) {
2563 // if errors, discard code
2564 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2565 if (l.head.hasTag(METHODDEF))
2566 ((JCMethodDecl) l.head).sym.code = null;
2567 }
2568 }
2569 cdef.defs = List.nil(); // discard trees
|