47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.EndPosTable;
49 import com.sun.tools.javac.tree.JCTree.*;
50
51 import static com.sun.tools.javac.code.Flags.*;
52 import static com.sun.tools.javac.code.Kinds.Kind.*;
53 import static com.sun.tools.javac.code.TypeTag.*;
54 import static com.sun.tools.javac.jvm.ByteCodes.*;
55 import static com.sun.tools.javac.jvm.CRTFlags.*;
56 import static com.sun.tools.javac.main.Option.*;
57 import static com.sun.tools.javac.tree.JCTree.Tag.*;
58
59 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
60 *
61 * <p><b>This is NOT part of any supported API.
62 * If you write code that depends on this, you do so at your own risk.
63 * This code and its internal interfaces are subject to change or
64 * deletion without notice.</b>
65 */
66 public class Gen extends JCTree.Visitor {
67 protected static final Context.Key<Gen> genKey = new Context.Key<>();
68
69 private final Log log;
70 private final Symtab syms;
71 private final Check chk;
72 private final Resolve rs;
73 private final TreeMaker make;
74 private final Names names;
75 private final Target target;
76 private final Name accessDollar;
77 private final Types types;
78 private final Lower lower;
79 private final Annotate annotate;
80 private final StringConcat concat;
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
114 methodType = new MethodType(null, null, null, syms.methodClass);
115 accessDollar = names.
116 fromString("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 }
137
138 /** Switches
139 */
140 private final boolean lineDebugInfo;
141 private final boolean varDebugInfo;
142 private final boolean genCrt;
143 private final boolean debugCode;
144 private boolean disableVirtualizedPrivateInvoke;
145
146 /** Code buffer, set by genMethod.
147 */
148 private Code code;
149
150 /** Items structure, set by genMethod.
151 */
152 private Items items;
153
154 /** Environment for symbol lookup, set by genClass
159 */
160 private JCCompilationUnit toplevel;
161
162 /** The number of code-gen errors in this class.
163 */
164 private int nerrs = 0;
165
166 /** An object containing mappings of syntax trees to their
167 * ending source positions.
168 */
169 EndPosTable endPosTable;
170
171 boolean inCondSwitchExpression;
172 Chain switchExpressionTrueChain;
173 Chain switchExpressionFalseChain;
174 List<LocalItem> stackBeforeSwitchExpression;
175 LocalItem switchResult;
176 Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of();
177 ListBuffer<int[]> patternMatchingInvocationRanges;
178
179 /** Cache the symbol to reflect the qualifying type.
180 * key: corresponding type
181 * value: qualified symbol
182 */
183 Map<Type, Symbol> qualifiedSymbolCache;
184
185 /** Generate code to load an integer constant.
186 * @param n The integer to be loaded.
187 */
188 void loadIntConst(int n) {
189 items.makeImmediateItem(syms.intType, n).load();
190 }
191
192 /** The opcode that loads a zero constant of a given type code.
193 * @param tc The given type code (@see ByteCode).
194 */
195 public static int zero(int tc) {
196 switch(tc) {
197 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
198 return iconst_0;
248 if ((qualifier = qualifiedSymbolCache.get(site)) == null) {
249 qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol);
250 qualifiedSymbolCache.put(site, qualifier);
251 }
252 return sym.clone(qualifier);
253 }
254
255 if (sym.owner == site.tsym ||
256 (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
257 return sym;
258 }
259
260 // leave alone methods inherited from Object
261 // JLS 13.1.
262 if (sym.owner == syms.objectType.tsym)
263 return sym;
264
265 return sym.clone(site.tsym);
266 }
267
268 /** Insert a reference to given type in the constant pool,
269 * checking for an array with too many dimensions;
270 * return the reference's index.
271 * @param type The type for which a reference is inserted.
272 */
273 int makeRef(DiagnosticPosition pos, Type type) {
274 return poolWriter.putClass(checkDimension(pos, type));
275 }
276
277 /** Check if the given type is an array with too many dimensions.
278 */
279 private Type checkDimension(DiagnosticPosition pos, Type t) {
280 checkDimensionInternal(pos, t);
281 return t;
282 }
283
284 private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
285 switch (t.getTag()) {
286 case METHOD:
287 checkDimension(pos, t.getReturnType());
288 for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail)
289 checkDimension(pos, args.head);
290 break;
291 case ARRAY:
292 if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
293 log.error(pos, Errors.LimitDimensions);
294 nerrs++;
308 type,
309 env.enclMethod.sym);
310 code.newLocal(v);
311 return items.makeLocalItem(v);
312 }
313
314 /** Generate code to call a non-private method or constructor.
315 * @param pos Position to be used for error reporting.
316 * @param site The type of which the method is a member.
317 * @param name The method's name.
318 * @param argtypes The method's argument types.
319 * @param isStatic A flag that indicates whether we call a
320 * static or instance method.
321 */
322 void callMethod(DiagnosticPosition pos,
323 Type site, Name name, List<Type> argtypes,
324 boolean isStatic) {
325 Symbol msym = rs.
326 resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
327 if (isStatic) items.makeStaticItem(msym).invoke();
328 else items.makeMemberItem(msym, name == names.init).invoke();
329 }
330
331 /** Is the given method definition an access method
332 * resulting from a qualified super? This is signified by an odd
333 * access code.
334 */
335 private boolean isAccessSuper(JCMethodDecl enclMethod) {
336 return
337 (enclMethod.mods.flags & SYNTHETIC) != 0 &&
338 isOddAccessName(enclMethod.name);
339 }
340
341 /** Does given name start with "access$" and end in an odd digit?
342 */
343 private boolean isOddAccessName(Name name) {
344 return
345 name.startsWith(accessDollar) &&
346 (name.getByteAt(name.getByteLength() - 1) & 1) == 1;
347 }
348
531 /** Check a constant value and report if it is a string that is
532 * too large.
533 */
534 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
535 if (nerrs != 0 || // only complain about a long string once
536 constValue == null ||
537 !(constValue instanceof String str) ||
538 str.length() < PoolWriter.MAX_STRING_LENGTH)
539 return;
540 log.error(pos, Errors.LimitString);
541 nerrs++;
542 }
543
544 /** Insert instance initializer code into initial constructor.
545 * @param md The tree potentially representing a
546 * constructor's definition.
547 * @param initCode The list of instance initializer statements.
548 * @param initTAs Type annotations from the initializer expression.
549 */
550 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
551 if (md.name == names.init && TreeInfo.isInitialConstructor(md)) {
552 // We are seeing a constructor that does not call another
553 // constructor of the same class.
554 List<JCStatement> stats = md.body.stats;
555 ListBuffer<JCStatement> newstats = new ListBuffer<>();
556
557 if (stats.nonEmpty()) {
558 // Copy initializers of synthetic variables generated in
559 // the translation of inner classes.
560 while (TreeInfo.isSyntheticInit(stats.head)) {
561 newstats.append(stats.head);
562 stats = stats.tail;
563 }
564 // Copy superclass constructor call
565 newstats.append(stats.head);
566 stats = stats.tail;
567 // Copy remaining synthetic initializers.
568 while (stats.nonEmpty() &&
569 TreeInfo.isSyntheticInit(stats.head)) {
570 newstats.append(stats.head);
571 stats = stats.tail;
934 // is the method's return type.
935 this.pt = tree.sym.erasure(types).getReturnType();
936
937 checkDimension(tree.pos(), tree.sym.erasure(types));
938 genMethod(tree, localEnv, false);
939 }
940 //where
941 /** Generate code for a method.
942 * @param tree The tree representing the method definition.
943 * @param env The environment current for the method body.
944 * @param fatcode A flag that indicates whether all jumps are
945 * within 32K. We first invoke this method under
946 * the assumption that fatcode == false, i.e. all
947 * jumps are within 32K. If this fails, fatcode
948 * is set to true and we try again.
949 */
950 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
951 MethodSymbol meth = tree.sym;
952 int extras = 0;
953 // Count up extra parameters
954 if (meth.isConstructor()) {
955 extras++;
956 if (meth.enclClass().isInner() &&
957 !meth.enclClass().isStatic()) {
958 extras++;
959 }
960 } else if ((tree.mods.flags & STATIC) == 0) {
961 extras++;
962 }
963 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
964 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras >
965 ClassFile.MAX_PARAMETERS) {
966 log.error(tree.pos(), Errors.LimitParameters);
967 nerrs++;
968 }
969
970 else if (tree.body != null) {
971 // Create a new code structure and initialize it.
972 int startpcCrt = initCode(tree, env, fatcode);
973
974 try {
975 genStat(tree.body, env);
976 } catch (CodeSizeOverflow e) {
977 // Failed due to code limit, try again with jsr/ret
978 startpcCrt = initCode(tree, env, fatcode);
979 genStat(tree.body, env);
980 }
981
982 if (code.state.stacksize != 0) {
983 log.error(tree.body.pos(), Errors.StackSimError(tree.sym));
984 throw new AssertionError();
985 }
986
987 // If last statement could complete normally, insert a
988 // return at the end.
989 if (code.isAlive()) {
990 code.statBegin(TreeInfo.endPos(tree.body));
991 if (env.enclMethod == null ||
992 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
993 code.emitop0(return_);
994 } else {
995 // sometime dead code seems alive (4415991);
996 // generate a small loop instead
997 int startpc = code.entryPoint();
998 CondItem c = items.makeCondItem(goto_);
999 code.resolve(c.jumpTrue(), startpc);
1000 }
1001 }
1002 if (genCrt)
1003 code.crt.put(tree.body,
1004 CRT_BLOCK,
1005 startpcCrt,
1006 code.curCP());
1007
1008 code.endScopes(0);
1009
1010 // If we exceeded limits, panic
1011 if (code.checkLimits(tree.pos(), log)) {
1012 nerrs++;
1013 return;
1028
1029 // Fill in type annotation positions for exception parameters
1030 code.fillExceptionParameterPositions();
1031 }
1032 }
1033
1034 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1035 MethodSymbol meth = tree.sym;
1036
1037 // Create a new code structure.
1038 meth.code = code = new Code(meth,
1039 fatcode,
1040 lineDebugInfo ? toplevel.lineMap : null,
1041 varDebugInfo,
1042 stackMap,
1043 debugCode,
1044 genCrt ? new CRTable(tree, env.toplevel.endPositions)
1045 : null,
1046 syms,
1047 types,
1048 poolWriter);
1049 items = new Items(poolWriter, code, syms, types);
1050 if (code.debugCode) {
1051 System.err.println(meth + " for body " + tree);
1052 }
1053
1054 // If method is not static, create a new local variable address
1055 // for `this'.
1056 if ((tree.mods.flags & STATIC) == 0) {
1057 Type selfType = meth.owner.type;
1058 if (meth.isConstructor() && selfType != syms.objectType)
1059 selfType = UninitializedType.uninitializedThis(selfType);
1060 code.setDefined(
1061 code.newLocal(
1062 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1063 }
1064
1065 // Mark all parameters as defined from the beginning of
1066 // the method.
1067 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1068 checkDimension(l.head.pos(), l.head.sym.type);
1069 code.setDefined(code.newLocal(l.head.sym));
1070 }
1071
1072 // Get ready to generate code for method body.
1073 int startpcCrt = genCrt ? code.curCP() : 0;
1074 code.entryPoint();
1075
1076 // Suppress initial stackmap
1077 code.pendingStackMap = false;
1078
1079 return startpcCrt;
1080 }
1081
1082 public void visitVarDef(JCVariableDecl tree) {
1083 VarSymbol v = tree.sym;
1084 if (tree.init != null) {
1085 checkStringConstant(tree.init.pos(), v.getConstValue());
1086 if (v.getConstValue() == null || varDebugInfo) {
1087 Assert.check(code.isStatementStart());
1088 code.newLocal(v);
1089 genExpr(tree.init, v.erasure(types)).load();
1090 items.makeLocalItem(v).store();
1091 Assert.check(code.isStatementStart());
1092 }
1093 } else {
1094 code.newLocal(v);
1095 }
1096 checkDimension(tree.pos(), v.type);
1097 }
1098
1099 public void visitSkip(JCSkip tree) {
1100 }
1101
1102 public void visitBlock(JCBlock tree) {
1103 if (tree.patternMatchingCatch != null) {
1104 Set<JCMethodInvocation> prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch;
1105 ListBuffer<int[]> prevRanges = patternMatchingInvocationRanges;
1106 State startState = code.state.dup();
1107 try {
1108 invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle();
1109 patternMatchingInvocationRanges = new ListBuffer<>();
1110 doVisitBlock(tree);
1111 } finally {
1112 Chain skipCatch = code.branch(goto_);
1113 JCCatch handler = tree.patternMatchingCatch.handler();
1114 code.entryPoint(startState, handler.param.sym.type);
1115 genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList());
1116 code.resolve(skipCatch);
1125 private void doVisitBlock(JCBlock tree) {
1126 int limit = code.nextreg;
1127 Env<GenContext> localEnv = env.dup(tree, new GenContext());
1128 genStats(tree.stats, localEnv);
1129 // End the scope of all block-local variables in variable info.
1130 if (!env.tree.hasTag(METHODDEF)) {
1131 code.statBegin(tree.endpos);
1132 code.endScopes(limit);
1133 code.pendingStatPos = Position.NOPOS;
1134 }
1135 }
1136
1137 public void visitDoLoop(JCDoWhileLoop tree) {
1138 genLoop(tree, tree.body, tree.cond, List.nil(), false);
1139 }
1140
1141 public void visitWhileLoop(JCWhileLoop tree) {
1142 genLoop(tree, tree.body, tree.cond, List.nil(), true);
1143 }
1144
1145 public void visitForLoop(JCForLoop tree) {
1146 int limit = code.nextreg;
1147 genStats(tree.init, env);
1148 genLoop(tree, tree.body, tree.cond, tree.step, true);
1149 code.endScopes(limit);
1150 }
1151 //where
1152 /** Generate code for a loop.
1153 * @param loop The tree representing the loop.
1154 * @param body The loop's body.
1155 * @param cond The loop's controlling condition.
1156 * @param step "Step" statements to be inserted at end of
1157 * each iteration.
1158 * @param testFirst True if the loop test belongs before the body.
1159 */
1160 private void genLoop(JCStatement loop,
1161 JCStatement body,
1162 JCExpression cond,
1163 List<JCExpressionStatement> step,
1164 boolean testFirst) {
2040 result = arr;
2041 } else {
2042 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
2043 genExpr(l.head, syms.intType).load();
2044 }
2045 result = makeNewArray(tree.pos(), tree.type, tree.dims.length());
2046 }
2047 }
2048 //where
2049 /** Generate code to create an array with given element type and number
2050 * of dimensions.
2051 */
2052 Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
2053 Type elemtype = types.elemtype(type);
2054 if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) {
2055 log.error(pos, Errors.LimitDimensions);
2056 nerrs++;
2057 }
2058 int elemcode = Code.arraycode(elemtype);
2059 if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
2060 code.emitAnewarray(makeRef(pos, elemtype), type);
2061 } else if (elemcode == 1) {
2062 code.emitMultianewarray(ndims, makeRef(pos, type), type);
2063 } else {
2064 code.emitNewarray(elemcode, type);
2065 }
2066 return items.makeStackItem(type);
2067 }
2068
2069 public void visitParens(JCParens tree) {
2070 result = genExpr(tree.expr, tree.expr.type);
2071 }
2072
2073 public void visitAssign(JCAssign tree) {
2074 Item l = genExpr(tree.lhs, tree.lhs.type);
2075 genExpr(tree.rhs, tree.lhs.type).load();
2076 if (tree.rhs.type.hasTag(BOT)) {
2077 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
2078 for "regarding a reference as having some other type in a manner that can be proved
2079 correct at compile time."
2080 */
2266 code.emitop0(opcode >> preShift);
2267 opcode = opcode & 0xFF;
2268 }
2269 }
2270 if (opcode >= ifeq && opcode <= if_acmpne ||
2271 opcode == if_acmp_null || opcode == if_acmp_nonnull) {
2272 return items.makeCondItem(opcode);
2273 } else {
2274 code.emitop0(opcode);
2275 return items.makeStackItem(optype.restype);
2276 }
2277 }
2278
2279 public void visitTypeCast(JCTypeCast tree) {
2280 result = genExpr(tree.expr, tree.clazz.type).load();
2281 setTypeAnnotationPositions(tree.pos);
2282 // Additional code is only needed if we cast to a reference type
2283 // which is not statically a supertype of the expression's type.
2284 // For basic types, the coerce(...) in genExpr(...) will do
2285 // the conversion.
2286 if (!tree.clazz.type.isPrimitive() &&
2287 !types.isSameType(tree.expr.type, tree.clazz.type) &&
2288 types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
2289 code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
2290 }
2291 }
2292
2293 public void visitWildcard(JCWildcard tree) {
2294 throw new AssertionError(this.getClass().getName());
2295 }
2296
2297 public void visitTypeTest(JCInstanceOf tree) {
2298 genExpr(tree.expr, tree.expr.type).load();
2299 setTypeAnnotationPositions(tree.pos);
2300 code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
2301 result = items.makeStackItem(syms.booleanType);
2302 }
2303
2304 public void visitIndexed(JCArrayAccess tree) {
2305 genExpr(tree.indexed, tree.indexed.type).load();
2306 genExpr(tree.index, syms.intType).load();
2307 result = items.makeIndexedItem(tree.type);
2308 }
2309
2331 sym = binaryQualifier(sym, env.enclClass.type);
2332 result = items.makeStaticItem(sym);
2333 } else {
2334 items.makeThisItem().load();
2335 sym = binaryQualifier(sym, env.enclClass.type);
2336 result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym));
2337 }
2338 }
2339
2340 //where
2341 private boolean nonVirtualForPrivateAccess(Symbol sym) {
2342 boolean useVirtual = target.hasVirtualPrivateInvoke() &&
2343 !disableVirtualizedPrivateInvoke;
2344 return !useVirtual && ((sym.flags() & PRIVATE) != 0);
2345 }
2346
2347 public void visitSelect(JCFieldAccess tree) {
2348 Symbol sym = tree.sym;
2349
2350 if (tree.name == names._class) {
2351 code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
2352 result = items.makeStackItem(pt);
2353 return;
2354 }
2355
2356 Symbol ssym = TreeInfo.symbol(tree.selected);
2357
2358 // Are we selecting via super?
2359 boolean selectSuper =
2360 ssym != null && (ssym.kind == TYP || ssym.name == names._super);
2361
2362 // Are we accessing a member of the superclass in an access method
2363 // resulting from a qualified super?
2364 boolean accessSuper = isAccessSuper(env.enclMethod);
2365
2366 Item base = (selectSuper)
2367 ? items.makeSuperItem()
2368 : genExpr(tree.selected, tree.selected.type);
2369
2370 if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) {
2371 // We are seeing a variable that is constant but its selecting
2372 // expression is not.
2373 if ((sym.flags() & STATIC) != 0) {
2374 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2390 if ((sym.flags() & STATIC) != 0) {
2391 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2392 base = base.load();
2393 base.drop();
2394 result = items.makeStaticItem(sym);
2395 } else {
2396 base.load();
2397 if (sym == syms.lengthVar) {
2398 code.emitop0(arraylength);
2399 result = items.makeStackItem(syms.intType);
2400 } else {
2401 result = items.
2402 makeMemberItem(sym,
2403 nonVirtualForPrivateAccess(sym) ||
2404 selectSuper || accessSuper);
2405 }
2406 }
2407 }
2408 }
2409
2410 public boolean isInvokeDynamic(Symbol sym) {
2411 return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
2412 }
2413
2414 public void visitLiteral(JCLiteral tree) {
2415 if (tree.type.hasTag(BOT)) {
2416 code.emitop0(aconst_null);
2417 result = items.makeStackItem(tree.type);
2418 }
2419 else
2420 result = items.makeImmediateItem(tree.type, tree.value);
2421 }
2422
2423 public void visitLetExpr(LetExpr tree) {
2424 code.resolvePending();
2425
2426 int limit = code.nextreg;
2427 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
2428 try {
2429 genStats(tree.defs, env);
2446 /* ************************************************************************
2447 * main method
2448 *************************************************************************/
2449
2450 /** Generate code for a class definition.
2451 * @param env The attribution environment that belongs to the
2452 * outermost class containing this class definition.
2453 * We need this for resolving some additional symbols.
2454 * @param cdef The tree representing the class definition.
2455 * @return True if code is generated with no errors.
2456 */
2457 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2458 try {
2459 attrEnv = env;
2460 ClassSymbol c = cdef.sym;
2461 this.toplevel = env.toplevel;
2462 this.endPosTable = toplevel.endPositions;
2463 /* method normalizeDefs() can add references to external classes into the constant pool
2464 */
2465 cdef.defs = normalizeDefs(cdef.defs, c);
2466 generateReferencesToPrunedTree(c);
2467 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2468 localEnv.toplevel = env.toplevel;
2469 localEnv.enclClass = cdef;
2470
2471 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2472 genDef(l.head, localEnv);
2473 }
2474 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2475 log.error(cdef.pos(), Errors.LimitPool);
2476 nerrs++;
2477 }
2478 if (nerrs != 0) {
2479 // if errors, discard code
2480 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2481 if (l.head.hasTag(METHODDEF))
2482 ((JCMethodDecl) l.head).sym.code = null;
2483 }
2484 }
2485 cdef.defs = List.nil(); // discard trees
|
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.EndPosTable;
49 import com.sun.tools.javac.tree.JCTree.*;
50
51 import static com.sun.tools.javac.code.Flags.*;
52 import static com.sun.tools.javac.code.Kinds.Kind.*;
53 import static com.sun.tools.javac.code.TypeTag.*;
54 import static com.sun.tools.javac.jvm.ByteCodes.*;
55 import static com.sun.tools.javac.jvm.CRTFlags.*;
56 import static com.sun.tools.javac.main.Option.*;
57 import static com.sun.tools.javac.tree.JCTree.Tag.*;
58
59 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
60 *
61 * <p><b>This is NOT part of any supported API.
62 * If you write code that depends on this, you do so at your own risk.
63 * This code and its internal interfaces are subject to change or
64 * deletion without notice.</b>
65 */
66 public class Gen extends JCTree.Visitor {
67 private static final Object[] NO_STATIC_ARGS = new Object[0];
68 protected static final Context.Key<Gen> genKey = new Context.Key<>();
69
70 private final Log log;
71 private final Symtab syms;
72 private final Check chk;
73 private final Resolve rs;
74 private final TreeMaker make;
75 private final Names names;
76 private final Target target;
77 private final Name accessDollar;
78 private final Types types;
79 private final Lower lower;
80 private final Annotate annotate;
81 private final StringConcat concat;
82 private final TransValues transValues;
83
84 /** Format of stackmap tables to be generated. */
85 private final Code.StackMapFormat stackMap;
86
87 /** A type that serves as the expected type for all method expressions.
88 */
89 private final Type methodType;
90
91 public static Gen instance(Context context) {
92 Gen instance = context.get(genKey);
93 if (instance == null)
94 instance = new Gen(context);
95 return instance;
96 }
97
98 /** Constant pool writer, set by genClass.
99 */
100 final PoolWriter poolWriter;
101
102 @SuppressWarnings("this-escape")
103 protected Gen(Context context) {
104 context.put(genKey, this);
105
106 names = Names.instance(context);
107 log = Log.instance(context);
108 syms = Symtab.instance(context);
109 chk = Check.instance(context);
110 rs = Resolve.instance(context);
111 make = TreeMaker.instance(context);
112 target = Target.instance(context);
113 types = Types.instance(context);
114 concat = StringConcat.instance(context);
115
116 methodType = new MethodType(null, null, null, syms.methodClass);
117 accessDollar = names.
118 fromString("access" + target.syntheticNameChar());
119 lower = Lower.instance(context);
120 transValues = TransValues.instance(context);
121
122 Options options = Options.instance(context);
123 lineDebugInfo =
124 options.isUnset(G_CUSTOM) ||
125 options.isSet(G_CUSTOM, "lines");
126 varDebugInfo =
127 options.isUnset(G_CUSTOM)
128 ? options.isSet(G)
129 : options.isSet(G_CUSTOM, "vars");
130 genCrt = options.isSet(XJCOV);
131 debugCode = options.isSet("debug.code");
132 disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
133 poolWriter = new PoolWriter(types, names);
134
135 // ignore cldc because we cannot have both stackmap formats
136 this.stackMap = StackMapFormat.JSR202;
137 annotate = Annotate.instance(context);
138 Source source = Source.instance(context);
139 allowPrimitiveClasses = Source.Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
140 qualifiedSymbolCache = new HashMap<>();
141 }
142
143 /** Switches
144 */
145 private final boolean lineDebugInfo;
146 private final boolean varDebugInfo;
147 private final boolean genCrt;
148 private final boolean debugCode;
149 private boolean disableVirtualizedPrivateInvoke;
150
151 /** Code buffer, set by genMethod.
152 */
153 private Code code;
154
155 /** Items structure, set by genMethod.
156 */
157 private Items items;
158
159 /** Environment for symbol lookup, set by genClass
164 */
165 private JCCompilationUnit toplevel;
166
167 /** The number of code-gen errors in this class.
168 */
169 private int nerrs = 0;
170
171 /** An object containing mappings of syntax trees to their
172 * ending source positions.
173 */
174 EndPosTable endPosTable;
175
176 boolean inCondSwitchExpression;
177 Chain switchExpressionTrueChain;
178 Chain switchExpressionFalseChain;
179 List<LocalItem> stackBeforeSwitchExpression;
180 LocalItem switchResult;
181 Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of();
182 ListBuffer<int[]> patternMatchingInvocationRanges;
183
184 boolean allowPrimitiveClasses;
185
186 /** Cache the symbol to reflect the qualifying type.
187 * key: corresponding type
188 * value: qualified symbol
189 */
190 Map<Type, Symbol> qualifiedSymbolCache;
191
192 /** Generate code to load an integer constant.
193 * @param n The integer to be loaded.
194 */
195 void loadIntConst(int n) {
196 items.makeImmediateItem(syms.intType, n).load();
197 }
198
199 /** The opcode that loads a zero constant of a given type code.
200 * @param tc The given type code (@see ByteCode).
201 */
202 public static int zero(int tc) {
203 switch(tc) {
204 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
205 return iconst_0;
255 if ((qualifier = qualifiedSymbolCache.get(site)) == null) {
256 qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol);
257 qualifiedSymbolCache.put(site, qualifier);
258 }
259 return sym.clone(qualifier);
260 }
261
262 if (sym.owner == site.tsym ||
263 (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
264 return sym;
265 }
266
267 // leave alone methods inherited from Object
268 // JLS 13.1.
269 if (sym.owner == syms.objectType.tsym)
270 return sym;
271
272 return sym.clone(site.tsym);
273 }
274
275 /** Insert a reference to given type in the constant pool,
276 * checking for an array with too many dimensions;
277 * return the reference's index.
278 * @param type The type for which a reference is inserted.
279 */
280 int makeRef(DiagnosticPosition pos, Type type, boolean emitQtype) {
281 checkDimension(pos, type);
282 if (emitQtype) {
283 return poolWriter.putClass(new ConstantPoolQType(type, types));
284 } else {
285 return poolWriter.putClass(type);
286 }
287 }
288
289 /** Insert a reference to given type in the constant pool,
290 * checking for an array with too many dimensions;
291 * return the reference's index.
292 * @param type The type for which a reference is inserted.
293 */
294 int makeRef(DiagnosticPosition pos, Type type) {
295 return makeRef(pos, type, false);
296 }
297
298 /** Check if the given type is an array with too many dimensions.
299 */
300 private Type checkDimension(DiagnosticPosition pos, Type t) {
301 checkDimensionInternal(pos, t);
302 return t;
303 }
304
305 private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
306 switch (t.getTag()) {
307 case METHOD:
308 checkDimension(pos, t.getReturnType());
309 for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail)
310 checkDimension(pos, args.head);
311 break;
312 case ARRAY:
313 if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
314 log.error(pos, Errors.LimitDimensions);
315 nerrs++;
329 type,
330 env.enclMethod.sym);
331 code.newLocal(v);
332 return items.makeLocalItem(v);
333 }
334
335 /** Generate code to call a non-private method or constructor.
336 * @param pos Position to be used for error reporting.
337 * @param site The type of which the method is a member.
338 * @param name The method's name.
339 * @param argtypes The method's argument types.
340 * @param isStatic A flag that indicates whether we call a
341 * static or instance method.
342 */
343 void callMethod(DiagnosticPosition pos,
344 Type site, Name name, List<Type> argtypes,
345 boolean isStatic) {
346 Symbol msym = rs.
347 resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
348 if (isStatic) items.makeStaticItem(msym).invoke();
349 else items.makeMemberItem(msym, names.isInitOrVNew(name)).invoke();
350 }
351
352 /** Is the given method definition an access method
353 * resulting from a qualified super? This is signified by an odd
354 * access code.
355 */
356 private boolean isAccessSuper(JCMethodDecl enclMethod) {
357 return
358 (enclMethod.mods.flags & SYNTHETIC) != 0 &&
359 isOddAccessName(enclMethod.name);
360 }
361
362 /** Does given name start with "access$" and end in an odd digit?
363 */
364 private boolean isOddAccessName(Name name) {
365 return
366 name.startsWith(accessDollar) &&
367 (name.getByteAt(name.getByteLength() - 1) & 1) == 1;
368 }
369
552 /** Check a constant value and report if it is a string that is
553 * too large.
554 */
555 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
556 if (nerrs != 0 || // only complain about a long string once
557 constValue == null ||
558 !(constValue instanceof String str) ||
559 str.length() < PoolWriter.MAX_STRING_LENGTH)
560 return;
561 log.error(pos, Errors.LimitString);
562 nerrs++;
563 }
564
565 /** Insert instance initializer code into initial constructor.
566 * @param md The tree potentially representing a
567 * constructor's definition.
568 * @param initCode The list of instance initializer statements.
569 * @param initTAs Type annotations from the initializer expression.
570 */
571 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
572 if (names.isInitOrVNew(md.name) && TreeInfo.isInitialConstructor(md)) {
573 // We are seeing a constructor that does not call another
574 // constructor of the same class.
575 List<JCStatement> stats = md.body.stats;
576 ListBuffer<JCStatement> newstats = new ListBuffer<>();
577
578 if (stats.nonEmpty()) {
579 // Copy initializers of synthetic variables generated in
580 // the translation of inner classes.
581 while (TreeInfo.isSyntheticInit(stats.head)) {
582 newstats.append(stats.head);
583 stats = stats.tail;
584 }
585 // Copy superclass constructor call
586 newstats.append(stats.head);
587 stats = stats.tail;
588 // Copy remaining synthetic initializers.
589 while (stats.nonEmpty() &&
590 TreeInfo.isSyntheticInit(stats.head)) {
591 newstats.append(stats.head);
592 stats = stats.tail;
955 // is the method's return type.
956 this.pt = tree.sym.erasure(types).getReturnType();
957
958 checkDimension(tree.pos(), tree.sym.erasure(types));
959 genMethod(tree, localEnv, false);
960 }
961 //where
962 /** Generate code for a method.
963 * @param tree The tree representing the method definition.
964 * @param env The environment current for the method body.
965 * @param fatcode A flag that indicates whether all jumps are
966 * within 32K. We first invoke this method under
967 * the assumption that fatcode == false, i.e. all
968 * jumps are within 32K. If this fails, fatcode
969 * is set to true and we try again.
970 */
971 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
972 MethodSymbol meth = tree.sym;
973 int extras = 0;
974 // Count up extra parameters
975 if (meth.isInitOrVNew()) {
976 extras++;
977 if (meth.enclClass().isInner() &&
978 !meth.enclClass().isStatic()) {
979 extras++;
980 }
981 } else if ((tree.mods.flags & STATIC) == 0) {
982 extras++;
983 }
984 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
985 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras >
986 ClassFile.MAX_PARAMETERS) {
987 log.error(tree.pos(), Errors.LimitParameters);
988 nerrs++;
989 }
990
991 else if (tree.body != null) {
992 // Create a new code structure and initialize it.
993 int startpcCrt = initCode(tree, env, fatcode);
994
995 try {
996 genStat(tree.body, env);
997 } catch (CodeSizeOverflow e) {
998 // Failed due to code limit, try again with jsr/ret
999 startpcCrt = initCode(tree, env, fatcode);
1000 genStat(tree.body, env);
1001 }
1002
1003 if (code.state.stacksize != 0) {
1004 log.error(tree.body.pos(), Errors.StackSimError(tree.sym));
1005 throw new AssertionError();
1006 }
1007
1008 // If last statement could complete normally, insert a
1009 // return at the end.
1010 if (code.isAlive()) {
1011 code.statBegin(TreeInfo.endPos(tree.body));
1012 if (env.enclMethod == null ||
1013 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
1014 code.emitop0(return_);
1015 } else if (env.enclMethod.sym.isValueObjectFactory()) {
1016 items.makeLocalItem(env.enclMethod.factoryProduct).load();
1017 code.emitop0(areturn);
1018 } else {
1019 // sometime dead code seems alive (4415991);
1020 // generate a small loop instead
1021 int startpc = code.entryPoint();
1022 CondItem c = items.makeCondItem(goto_);
1023 code.resolve(c.jumpTrue(), startpc);
1024 }
1025 }
1026 if (genCrt)
1027 code.crt.put(tree.body,
1028 CRT_BLOCK,
1029 startpcCrt,
1030 code.curCP());
1031
1032 code.endScopes(0);
1033
1034 // If we exceeded limits, panic
1035 if (code.checkLimits(tree.pos(), log)) {
1036 nerrs++;
1037 return;
1052
1053 // Fill in type annotation positions for exception parameters
1054 code.fillExceptionParameterPositions();
1055 }
1056 }
1057
1058 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1059 MethodSymbol meth = tree.sym;
1060
1061 // Create a new code structure.
1062 meth.code = code = new Code(meth,
1063 fatcode,
1064 lineDebugInfo ? toplevel.lineMap : null,
1065 varDebugInfo,
1066 stackMap,
1067 debugCode,
1068 genCrt ? new CRTable(tree, env.toplevel.endPositions)
1069 : null,
1070 syms,
1071 types,
1072 poolWriter,
1073 allowPrimitiveClasses);
1074 items = new Items(poolWriter, code, syms, types);
1075 if (code.debugCode) {
1076 System.err.println(meth + " for body " + tree);
1077 }
1078
1079 // If method is not static, create a new local variable address
1080 // for `this'.
1081 if ((tree.mods.flags & STATIC) == 0) {
1082 Type selfType = meth.owner.type;
1083 if (meth.isInitOrVNew() && selfType != syms.objectType)
1084 selfType = UninitializedType.uninitializedThis(selfType);
1085 code.setDefined(
1086 code.newLocal(
1087 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1088 }
1089
1090 // Mark all parameters as defined from the beginning of
1091 // the method.
1092 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1093 checkDimension(l.head.pos(), l.head.sym.type);
1094 code.setDefined(code.newLocal(l.head.sym));
1095 }
1096
1097 // Get ready to generate code for method body.
1098 int startpcCrt = genCrt ? code.curCP() : 0;
1099 code.entryPoint();
1100
1101 // Suppress initial stackmap
1102 code.pendingStackMap = false;
1103
1104 return startpcCrt;
1105 }
1106
1107 public void visitVarDef(JCVariableDecl tree) {
1108 VarSymbol v = tree.sym;
1109 if (tree.init != null) {
1110 checkStringConstant(tree.init.pos(), v.getConstValue());
1111 if (v.getConstValue() == null || varDebugInfo) {
1112 Assert.check(code.isStatementStart());
1113 code.newLocal(v);
1114 genExpr(tree.init, v.erasure(types)).load();
1115 items.makeLocalItem(v).store();
1116 Assert.check(code.isStatementStart());
1117 }
1118 } else {
1119 code.newLocal(v);
1120 }
1121 checkDimension(tree.pos(), v.type);
1122 Type localType = v.erasure(types);
1123 if (localType.requiresPreload(env.enclClass.sym)) {
1124 poolWriter.enterPreloadClass((ClassSymbol) localType.tsym);
1125 }
1126 }
1127
1128 public void visitSkip(JCSkip tree) {
1129 }
1130
1131 public void visitBlock(JCBlock tree) {
1132 if (tree.patternMatchingCatch != null) {
1133 Set<JCMethodInvocation> prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch;
1134 ListBuffer<int[]> prevRanges = patternMatchingInvocationRanges;
1135 State startState = code.state.dup();
1136 try {
1137 invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle();
1138 patternMatchingInvocationRanges = new ListBuffer<>();
1139 doVisitBlock(tree);
1140 } finally {
1141 Chain skipCatch = code.branch(goto_);
1142 JCCatch handler = tree.patternMatchingCatch.handler();
1143 code.entryPoint(startState, handler.param.sym.type);
1144 genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList());
1145 code.resolve(skipCatch);
1154 private void doVisitBlock(JCBlock tree) {
1155 int limit = code.nextreg;
1156 Env<GenContext> localEnv = env.dup(tree, new GenContext());
1157 genStats(tree.stats, localEnv);
1158 // End the scope of all block-local variables in variable info.
1159 if (!env.tree.hasTag(METHODDEF)) {
1160 code.statBegin(tree.endpos);
1161 code.endScopes(limit);
1162 code.pendingStatPos = Position.NOPOS;
1163 }
1164 }
1165
1166 public void visitDoLoop(JCDoWhileLoop tree) {
1167 genLoop(tree, tree.body, tree.cond, List.nil(), false);
1168 }
1169
1170 public void visitWhileLoop(JCWhileLoop tree) {
1171 genLoop(tree, tree.body, tree.cond, List.nil(), true);
1172 }
1173
1174 public void visitWithField(JCWithField tree) {
1175 switch(tree.field.getTag()) {
1176 case IDENT:
1177 Symbol sym = ((JCIdent) tree.field).sym;
1178 items.makeThisItem().load();
1179 genExpr(tree.value, tree.field.type).load();
1180 sym = binaryQualifier(sym, env.enclClass.type);
1181 code.emitop2(withfield, sym, PoolWriter::putMember);
1182 result = items.makeStackItem(tree.type);
1183 break;
1184 case SELECT:
1185 JCFieldAccess fieldAccess = (JCFieldAccess) tree.field;
1186 sym = TreeInfo.symbol(fieldAccess);
1187 // JDK-8207332: To maintain the order of side effects, must compute value ahead of field
1188 genExpr(tree.value, tree.field.type).load();
1189 genExpr(fieldAccess.selected, fieldAccess.selected.type).load();
1190 if (Code.width(tree.field.type) == 2) {
1191 code.emitop0(dup_x2);
1192 code.emitop0(pop);
1193 } else {
1194 code.emitop0(swap);
1195 }
1196 sym = binaryQualifier(sym, fieldAccess.selected.type);
1197 code.emitop2(withfield, sym, PoolWriter::putMember);
1198 result = items.makeStackItem(tree.type);
1199 break;
1200 default:
1201 Assert.check(false);
1202 }
1203 }
1204
1205 public void visitForLoop(JCForLoop tree) {
1206 int limit = code.nextreg;
1207 genStats(tree.init, env);
1208 genLoop(tree, tree.body, tree.cond, tree.step, true);
1209 code.endScopes(limit);
1210 }
1211 //where
1212 /** Generate code for a loop.
1213 * @param loop The tree representing the loop.
1214 * @param body The loop's body.
1215 * @param cond The loop's controlling condition.
1216 * @param step "Step" statements to be inserted at end of
1217 * each iteration.
1218 * @param testFirst True if the loop test belongs before the body.
1219 */
1220 private void genLoop(JCStatement loop,
1221 JCStatement body,
1222 JCExpression cond,
1223 List<JCExpressionStatement> step,
1224 boolean testFirst) {
2100 result = arr;
2101 } else {
2102 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
2103 genExpr(l.head, syms.intType).load();
2104 }
2105 result = makeNewArray(tree.pos(), tree.type, tree.dims.length());
2106 }
2107 }
2108 //where
2109 /** Generate code to create an array with given element type and number
2110 * of dimensions.
2111 */
2112 Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
2113 Type elemtype = types.elemtype(type);
2114 if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) {
2115 log.error(pos, Errors.LimitDimensions);
2116 nerrs++;
2117 }
2118 int elemcode = Code.arraycode(elemtype);
2119 if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
2120 code.emitAnewarray(makeRef(pos, elemtype, elemtype.isPrimitiveClass()), type);
2121 } else if (elemcode == 1) {
2122 code.emitMultianewarray(ndims, makeRef(pos, type), type);
2123 } else {
2124 code.emitNewarray(elemcode, type);
2125 }
2126 return items.makeStackItem(type);
2127 }
2128
2129 public void visitParens(JCParens tree) {
2130 result = genExpr(tree.expr, tree.expr.type);
2131 }
2132
2133 public void visitAssign(JCAssign tree) {
2134 Item l = genExpr(tree.lhs, tree.lhs.type);
2135 genExpr(tree.rhs, tree.lhs.type).load();
2136 if (tree.rhs.type.hasTag(BOT)) {
2137 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
2138 for "regarding a reference as having some other type in a manner that can be proved
2139 correct at compile time."
2140 */
2326 code.emitop0(opcode >> preShift);
2327 opcode = opcode & 0xFF;
2328 }
2329 }
2330 if (opcode >= ifeq && opcode <= if_acmpne ||
2331 opcode == if_acmp_null || opcode == if_acmp_nonnull) {
2332 return items.makeCondItem(opcode);
2333 } else {
2334 code.emitop0(opcode);
2335 return items.makeStackItem(optype.restype);
2336 }
2337 }
2338
2339 public void visitTypeCast(JCTypeCast tree) {
2340 result = genExpr(tree.expr, tree.clazz.type).load();
2341 setTypeAnnotationPositions(tree.pos);
2342 // Additional code is only needed if we cast to a reference type
2343 // which is not statically a supertype of the expression's type.
2344 // For basic types, the coerce(...) in genExpr(...) will do
2345 // the conversion.
2346 // primitive reference conversion is a nop when we bifurcate the primitive class, as the VM sees a subtyping relationship.
2347 if (!tree.clazz.type.isPrimitive() &&
2348 !types.isSameType(tree.expr.type, tree.clazz.type) &&
2349 (!tree.clazz.type.isReferenceProjection() || !types.isSameType(tree.clazz.type.valueProjection(), tree.expr.type) || true) &&
2350 !types.isSubtype(tree.expr.type, tree.clazz.type)) {
2351 checkDimension(tree.pos(), tree.clazz.type);
2352 if (tree.clazz.type.isPrimitiveClass()) {
2353 code.emitop2(checkcast, new ConstantPoolQType(tree.clazz.type, types), PoolWriter::putClass);
2354 } else {
2355 code.emitop2(checkcast, tree.clazz.type, PoolWriter::putClass);
2356 }
2357
2358 }
2359 }
2360
2361 public void visitWildcard(JCWildcard tree) {
2362 throw new AssertionError(this.getClass().getName());
2363 }
2364
2365 public void visitTypeTest(JCInstanceOf tree) {
2366 genExpr(tree.expr, tree.expr.type).load();
2367 setTypeAnnotationPositions(tree.pos);
2368 code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
2369 result = items.makeStackItem(syms.booleanType);
2370 }
2371
2372 public void visitIndexed(JCArrayAccess tree) {
2373 genExpr(tree.indexed, tree.indexed.type).load();
2374 genExpr(tree.index, syms.intType).load();
2375 result = items.makeIndexedItem(tree.type);
2376 }
2377
2399 sym = binaryQualifier(sym, env.enclClass.type);
2400 result = items.makeStaticItem(sym);
2401 } else {
2402 items.makeThisItem().load();
2403 sym = binaryQualifier(sym, env.enclClass.type);
2404 result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym));
2405 }
2406 }
2407
2408 //where
2409 private boolean nonVirtualForPrivateAccess(Symbol sym) {
2410 boolean useVirtual = target.hasVirtualPrivateInvoke() &&
2411 !disableVirtualizedPrivateInvoke;
2412 return !useVirtual && ((sym.flags() & PRIVATE) != 0);
2413 }
2414
2415 public void visitSelect(JCFieldAccess tree) {
2416 Symbol sym = tree.sym;
2417
2418 if (tree.name == names._class) {
2419 code.emitLdc((LoadableConstant) tree.selected.type, makeRef(tree.pos(), tree.selected.type, tree.selected.type.isPrimitiveClass()));
2420 result = items.makeStackItem(pt);
2421 return;
2422 }
2423
2424 Symbol ssym = TreeInfo.symbol(tree.selected);
2425
2426 // Are we selecting via super?
2427 boolean selectSuper =
2428 ssym != null && (ssym.kind == TYP || ssym.name == names._super);
2429
2430 // Are we accessing a member of the superclass in an access method
2431 // resulting from a qualified super?
2432 boolean accessSuper = isAccessSuper(env.enclMethod);
2433
2434 Item base = (selectSuper)
2435 ? items.makeSuperItem()
2436 : genExpr(tree.selected, tree.selected.type);
2437
2438 if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) {
2439 // We are seeing a variable that is constant but its selecting
2440 // expression is not.
2441 if ((sym.flags() & STATIC) != 0) {
2442 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2458 if ((sym.flags() & STATIC) != 0) {
2459 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2460 base = base.load();
2461 base.drop();
2462 result = items.makeStaticItem(sym);
2463 } else {
2464 base.load();
2465 if (sym == syms.lengthVar) {
2466 code.emitop0(arraylength);
2467 result = items.makeStackItem(syms.intType);
2468 } else {
2469 result = items.
2470 makeMemberItem(sym,
2471 nonVirtualForPrivateAccess(sym) ||
2472 selectSuper || accessSuper);
2473 }
2474 }
2475 }
2476 }
2477
2478 public void visitDefaultValue(JCDefaultValue tree) {
2479 if (tree.type.isValueClass()) {
2480 code.emitop2(aconst_init, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
2481 } else if (tree.type.isReference()) {
2482 code.emitop0(aconst_null);
2483 } else {
2484 code.emitop0(zero(Code.typecode(tree.type)));
2485 }
2486 result = items.makeStackItem(tree.type);
2487 return;
2488 }
2489
2490 public boolean isInvokeDynamic(Symbol sym) {
2491 return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
2492 }
2493
2494 public void visitLiteral(JCLiteral tree) {
2495 if (tree.type.hasTag(BOT)) {
2496 code.emitop0(aconst_null);
2497 result = items.makeStackItem(tree.type);
2498 }
2499 else
2500 result = items.makeImmediateItem(tree.type, tree.value);
2501 }
2502
2503 public void visitLetExpr(LetExpr tree) {
2504 code.resolvePending();
2505
2506 int limit = code.nextreg;
2507 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
2508 try {
2509 genStats(tree.defs, env);
2526 /* ************************************************************************
2527 * main method
2528 *************************************************************************/
2529
2530 /** Generate code for a class definition.
2531 * @param env The attribution environment that belongs to the
2532 * outermost class containing this class definition.
2533 * We need this for resolving some additional symbols.
2534 * @param cdef The tree representing the class definition.
2535 * @return True if code is generated with no errors.
2536 */
2537 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2538 try {
2539 attrEnv = env;
2540 ClassSymbol c = cdef.sym;
2541 this.toplevel = env.toplevel;
2542 this.endPosTable = toplevel.endPositions;
2543 /* method normalizeDefs() can add references to external classes into the constant pool
2544 */
2545 cdef.defs = normalizeDefs(cdef.defs, c);
2546 cdef = transValues.translateTopLevelClass(cdef, make);
2547 generateReferencesToPrunedTree(c);
2548 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2549 localEnv.toplevel = env.toplevel;
2550 localEnv.enclClass = cdef;
2551
2552 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2553 genDef(l.head, localEnv);
2554 }
2555 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2556 log.error(cdef.pos(), Errors.LimitPool);
2557 nerrs++;
2558 }
2559 if (nerrs != 0) {
2560 // if errors, discard code
2561 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2562 if (l.head.hasTag(METHODDEF))
2563 ((JCMethodDecl) l.head).sym.code = null;
2564 }
2565 }
2566 cdef.defs = List.nil(); // discard trees
|