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 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 = names.
115 fromString("access" + target.syntheticNameChar());
116 lower = Lower.instance(context);
117
118 Options options = Options.instance(context);
119 lineDebugInfo =
120 options.isUnset(G_CUSTOM) ||
121 options.isSet(G_CUSTOM, "lines");
122 varDebugInfo =
123 options.isUnset(G_CUSTOM)
124 ? options.isSet(G)
125 : options.isSet(G_CUSTOM, "vars");
126 genCrt = options.isSet(XJCOV);
127 debugCode = options.isSet("debug.code");
128 disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
129 poolWriter = new PoolWriter(types, names);
130
131 // ignore cldc because we cannot have both stackmap formats
132 this.stackMap = StackMapFormat.JSR202;
133 annotate = Annotate.instance(context);
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 */
157 */
158 private JCCompilationUnit toplevel;
159
160 /** The number of code-gen errors in this class.
161 */
162 private int nerrs = 0;
163
164 /** An object containing mappings of syntax trees to their
165 * ending source positions.
166 */
167 EndPosTable endPosTable;
168
169 boolean inCondSwitchExpression;
170 Chain switchExpressionTrueChain;
171 Chain switchExpressionFalseChain;
172 List<LocalItem> stackBeforeSwitchExpression;
173 LocalItem switchResult;
174 Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of();
175 ListBuffer<int[]> patternMatchingInvocationRanges;
176
177 /** Generate code to load an integer constant.
178 * @param n The integer to be loaded.
179 */
180 void loadIntConst(int n) {
181 items.makeImmediateItem(syms.intType, n).load();
182 }
183
184 /** The opcode that loads a zero constant of a given type code.
185 * @param tc The given type code (@see ByteCode).
186 */
187 public static int zero(int tc) {
188 switch(tc) {
189 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
190 return iconst_0;
191 case LONGcode:
192 return lconst_0;
193 case FLOATcode:
194 return fconst_0;
195 case DOUBLEcode:
196 return dconst_0;
200 }
201
202 /** The opcode that loads a one constant of a given type code.
203 * @param tc The given type code (@see ByteCode).
204 */
205 public static int one(int tc) {
206 return zero(tc) + 1;
207 }
208
209 /** Generate code to load -1 of the given type code (either int or long).
210 * @param tc The given type code (@see ByteCode).
211 */
212 void emitMinusOne(int tc) {
213 if (tc == LONGcode) {
214 items.makeImmediateItem(syms.longType, Long.valueOf(-1)).load();
215 } else {
216 code.emitop0(iconst_m1);
217 }
218 }
219
220 /** Insert a reference to given type in the constant pool,
221 * checking for an array with too many dimensions;
222 * return the reference's index.
223 * @param type The type for which a reference is inserted.
224 */
225 int makeRef(DiagnosticPosition pos, Type type) {
226 return poolWriter.putClass(checkDimension(pos, type));
227 }
228
229 /** Check if the given type is an array with too many dimensions.
230 */
231 private Type checkDimension(DiagnosticPosition pos, Type t) {
232 checkDimensionInternal(pos, t);
233 return t;
234 }
235
236 private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
237 switch (t.getTag()) {
238 case METHOD:
239 checkDimension(pos, t.getReturnType());
240 for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail)
241 checkDimension(pos, args.head);
242 break;
243 case ARRAY:
244 if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
245 log.error(pos, Errors.LimitDimensions);
246 nerrs++;
260 type,
261 env.enclMethod.sym);
262 code.newLocal(v);
263 return items.makeLocalItem(v);
264 }
265
266 /** Generate code to call a non-private method or constructor.
267 * @param pos Position to be used for error reporting.
268 * @param site The type of which the method is a member.
269 * @param name The method's name.
270 * @param argtypes The method's argument types.
271 * @param isStatic A flag that indicates whether we call a
272 * static or instance method.
273 */
274 void callMethod(DiagnosticPosition pos,
275 Type site, Name name, List<Type> argtypes,
276 boolean isStatic) {
277 Symbol msym = rs.
278 resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
279 if (isStatic) items.makeStaticItem(msym).invoke();
280 else items.makeMemberItem(msym, name == names.init).invoke();
281 }
282
283 /** Is the given method definition an access method
284 * resulting from a qualified super? This is signified by an odd
285 * access code.
286 */
287 private boolean isAccessSuper(JCMethodDecl enclMethod) {
288 return
289 (enclMethod.mods.flags & SYNTHETIC) != 0 &&
290 isOddAccessName(enclMethod.name);
291 }
292
293 /** Does given name start with "access$" and end in an odd digit?
294 */
295 private boolean isOddAccessName(Name name) {
296 return
297 name.startsWith(accessDollar) &&
298 (name.getByteAt(name.getByteLength() - 1) & 1) == 1;
299 }
300
483 /** Check a constant value and report if it is a string that is
484 * too large.
485 */
486 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
487 if (nerrs != 0 || // only complain about a long string once
488 constValue == null ||
489 !(constValue instanceof String str) ||
490 str.length() < PoolWriter.MAX_STRING_LENGTH)
491 return;
492 log.error(pos, Errors.LimitString);
493 nerrs++;
494 }
495
496 /** Insert instance initializer code into initial constructor.
497 * @param md The tree potentially representing a
498 * constructor's definition.
499 * @param initCode The list of instance initializer statements.
500 * @param initTAs Type annotations from the initializer expression.
501 */
502 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
503 if (md.name == names.init && TreeInfo.isInitialConstructor(md)) {
504 // We are seeing a constructor that does not call another
505 // constructor of the same class.
506 List<JCStatement> stats = md.body.stats;
507 ListBuffer<JCStatement> newstats = new ListBuffer<>();
508
509 if (stats.nonEmpty()) {
510 // Copy initializers of synthetic variables generated in
511 // the translation of inner classes.
512 while (TreeInfo.isSyntheticInit(stats.head)) {
513 newstats.append(stats.head);
514 stats = stats.tail;
515 }
516 // Copy superclass constructor call
517 newstats.append(stats.head);
518 stats = stats.tail;
519 // Copy remaining synthetic initializers.
520 while (stats.nonEmpty() &&
521 TreeInfo.isSyntheticInit(stats.head)) {
522 newstats.append(stats.head);
523 stats = stats.tail;
886 // is the method's return type.
887 this.pt = tree.sym.erasure(types).getReturnType();
888
889 checkDimension(tree.pos(), tree.sym.erasure(types));
890 genMethod(tree, localEnv, false);
891 }
892 //where
893 /** Generate code for a method.
894 * @param tree The tree representing the method definition.
895 * @param env The environment current for the method body.
896 * @param fatcode A flag that indicates whether all jumps are
897 * within 32K. We first invoke this method under
898 * the assumption that fatcode == false, i.e. all
899 * jumps are within 32K. If this fails, fatcode
900 * is set to true and we try again.
901 */
902 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
903 MethodSymbol meth = tree.sym;
904 int extras = 0;
905 // Count up extra parameters
906 if (meth.isConstructor()) {
907 extras++;
908 if (meth.enclClass().isInner() &&
909 !meth.enclClass().isStatic()) {
910 extras++;
911 }
912 } else if ((tree.mods.flags & STATIC) == 0) {
913 extras++;
914 }
915 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
916 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras >
917 ClassFile.MAX_PARAMETERS) {
918 log.error(tree.pos(), Errors.LimitParameters);
919 nerrs++;
920 }
921
922 else if (tree.body != null) {
923 // Create a new code structure and initialize it.
924 int startpcCrt = initCode(tree, env, fatcode);
925
926 try {
927 genStat(tree.body, env);
928 } catch (CodeSizeOverflow e) {
929 // Failed due to code limit, try again with jsr/ret
930 startpcCrt = initCode(tree, env, fatcode);
931 genStat(tree.body, env);
932 }
933
934 if (code.state.stacksize != 0) {
935 log.error(tree.body.pos(), Errors.StackSimError(tree.sym));
936 throw new AssertionError();
937 }
938
939 // If last statement could complete normally, insert a
940 // return at the end.
941 if (code.isAlive()) {
942 code.statBegin(TreeInfo.endPos(tree.body));
943 if (env.enclMethod == null ||
944 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
945 code.emitop0(return_);
946 } else {
947 // sometime dead code seems alive (4415991);
948 // generate a small loop instead
949 int startpc = code.entryPoint();
950 CondItem c = items.makeCondItem(goto_);
951 code.resolve(c.jumpTrue(), startpc);
952 }
953 }
954 if (genCrt)
955 code.crt.put(tree.body,
956 CRT_BLOCK,
957 startpcCrt,
958 code.curCP());
959
960 code.endScopes(0);
961
962 // If we exceeded limits, panic
963 if (code.checkLimits(tree.pos(), log)) {
964 nerrs++;
965 return;
980
981 // Fill in type annotation positions for exception parameters
982 code.fillExceptionParameterPositions();
983 }
984 }
985
986 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
987 MethodSymbol meth = tree.sym;
988
989 // Create a new code structure.
990 meth.code = code = new Code(meth,
991 fatcode,
992 lineDebugInfo ? toplevel.lineMap : null,
993 varDebugInfo,
994 stackMap,
995 debugCode,
996 genCrt ? new CRTable(tree, env.toplevel.endPositions)
997 : null,
998 syms,
999 types,
1000 poolWriter);
1001 items = new Items(poolWriter, code, syms, types);
1002 if (code.debugCode) {
1003 System.err.println(meth + " for body " + tree);
1004 }
1005
1006 // If method is not static, create a new local variable address
1007 // for `this'.
1008 if ((tree.mods.flags & STATIC) == 0) {
1009 Type selfType = meth.owner.type;
1010 if (meth.isConstructor() && selfType != syms.objectType)
1011 selfType = UninitializedType.uninitializedThis(selfType);
1012 code.setDefined(
1013 code.newLocal(
1014 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1015 }
1016
1017 // Mark all parameters as defined from the beginning of
1018 // the method.
1019 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1020 checkDimension(l.head.pos(), l.head.sym.type);
1021 code.setDefined(code.newLocal(l.head.sym));
1022 }
1023
1024 // Get ready to generate code for method body.
1025 int startpcCrt = genCrt ? code.curCP() : 0;
1026 code.entryPoint();
1027
1028 // Suppress initial stackmap
1029 code.pendingStackMap = false;
1030
1031 return startpcCrt;
1032 }
1033
1034 public void visitVarDef(JCVariableDecl tree) {
1035 VarSymbol v = tree.sym;
1036 if (tree.init != null) {
1037 checkStringConstant(tree.init.pos(), v.getConstValue());
1038 if (v.getConstValue() == null || varDebugInfo) {
1039 Assert.check(code.isStatementStart());
1040 code.newLocal(v);
1041 genExpr(tree.init, v.erasure(types)).load();
1042 items.makeLocalItem(v).store();
1043 Assert.check(code.isStatementStart());
1044 }
1045 } else {
1046 code.newLocal(v);
1047 }
1048 checkDimension(tree.pos(), v.type);
1049 }
1050
1051 public void visitSkip(JCSkip tree) {
1052 }
1053
1054 public void visitBlock(JCBlock tree) {
1055 if (tree.patternMatchingCatch != null) {
1056 Set<JCMethodInvocation> prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch;
1057 ListBuffer<int[]> prevRanges = patternMatchingInvocationRanges;
1058 State startState = code.state.dup();
1059 try {
1060 invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle();
1061 patternMatchingInvocationRanges = new ListBuffer<>();
1062 doVisitBlock(tree);
1063 } finally {
1064 Chain skipCatch = code.branch(goto_);
1065 JCCatch handler = tree.patternMatchingCatch.handler();
1066 code.entryPoint(startState, handler.param.sym.type);
1067 genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList());
1068 code.resolve(skipCatch);
1077 private void doVisitBlock(JCBlock tree) {
1078 int limit = code.nextreg;
1079 Env<GenContext> localEnv = env.dup(tree, new GenContext());
1080 genStats(tree.stats, localEnv);
1081 // End the scope of all block-local variables in variable info.
1082 if (!env.tree.hasTag(METHODDEF)) {
1083 code.statBegin(tree.endpos);
1084 code.endScopes(limit);
1085 code.pendingStatPos = Position.NOPOS;
1086 }
1087 }
1088
1089 public void visitDoLoop(JCDoWhileLoop tree) {
1090 genLoop(tree, tree.body, tree.cond, List.nil(), false);
1091 }
1092
1093 public void visitWhileLoop(JCWhileLoop tree) {
1094 genLoop(tree, tree.body, tree.cond, List.nil(), true);
1095 }
1096
1097 public void visitForLoop(JCForLoop tree) {
1098 int limit = code.nextreg;
1099 genStats(tree.init, env);
1100 genLoop(tree, tree.body, tree.cond, tree.step, true);
1101 code.endScopes(limit);
1102 }
1103 //where
1104 /** Generate code for a loop.
1105 * @param loop The tree representing the loop.
1106 * @param body The loop's body.
1107 * @param cond The loop's controlling condition.
1108 * @param step "Step" statements to be inserted at end of
1109 * each iteration.
1110 * @param testFirst True if the loop test belongs before the body.
1111 */
1112 private void genLoop(JCStatement loop,
1113 JCStatement body,
1114 JCExpression cond,
1115 List<JCExpressionStatement> step,
1116 boolean testFirst) {
1992 result = arr;
1993 } else {
1994 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
1995 genExpr(l.head, syms.intType).load();
1996 }
1997 result = makeNewArray(tree.pos(), tree.type, tree.dims.length());
1998 }
1999 }
2000 //where
2001 /** Generate code to create an array with given element type and number
2002 * of dimensions.
2003 */
2004 Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
2005 Type elemtype = types.elemtype(type);
2006 if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) {
2007 log.error(pos, Errors.LimitDimensions);
2008 nerrs++;
2009 }
2010 int elemcode = Code.arraycode(elemtype);
2011 if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
2012 code.emitAnewarray(makeRef(pos, elemtype), type);
2013 } else if (elemcode == 1) {
2014 code.emitMultianewarray(ndims, makeRef(pos, type), type);
2015 } else {
2016 code.emitNewarray(elemcode, type);
2017 }
2018 return items.makeStackItem(type);
2019 }
2020
2021 public void visitParens(JCParens tree) {
2022 result = genExpr(tree.expr, tree.expr.type);
2023 }
2024
2025 public void visitAssign(JCAssign tree) {
2026 Item l = genExpr(tree.lhs, tree.lhs.type);
2027 genExpr(tree.rhs, tree.lhs.type).load();
2028 if (tree.rhs.type.hasTag(BOT)) {
2029 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
2030 for "regarding a reference as having some other type in a manner that can be proved
2031 correct at compile time."
2032 */
2218 code.emitop0(opcode >> preShift);
2219 opcode = opcode & 0xFF;
2220 }
2221 }
2222 if (opcode >= ifeq && opcode <= if_acmpne ||
2223 opcode == if_acmp_null || opcode == if_acmp_nonnull) {
2224 return items.makeCondItem(opcode);
2225 } else {
2226 code.emitop0(opcode);
2227 return items.makeStackItem(optype.restype);
2228 }
2229 }
2230
2231 public void visitTypeCast(JCTypeCast tree) {
2232 result = genExpr(tree.expr, tree.clazz.type).load();
2233 setTypeAnnotationPositions(tree.pos);
2234 // Additional code is only needed if we cast to a reference type
2235 // which is not statically a supertype of the expression's type.
2236 // For basic types, the coerce(...) in genExpr(...) will do
2237 // the conversion.
2238 if (!tree.clazz.type.isPrimitive() &&
2239 !types.isSameType(tree.expr.type, tree.clazz.type) &&
2240 types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
2241 code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
2242 }
2243 }
2244
2245 public void visitWildcard(JCWildcard tree) {
2246 throw new AssertionError(this.getClass().getName());
2247 }
2248
2249 public void visitTypeTest(JCInstanceOf tree) {
2250 genExpr(tree.expr, tree.expr.type).load();
2251 setTypeAnnotationPositions(tree.pos);
2252 code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
2253 result = items.makeStackItem(syms.booleanType);
2254 }
2255
2256 public void visitIndexed(JCArrayAccess tree) {
2257 genExpr(tree.indexed, tree.indexed.type).load();
2258 genExpr(tree.index, syms.intType).load();
2259 result = items.makeIndexedItem(tree.type);
2260 }
2261
2283 sym = types.binaryQualifier(sym, env.enclClass.type);
2284 result = items.makeStaticItem(sym);
2285 } else {
2286 items.makeThisItem().load();
2287 sym = types.binaryQualifier(sym, env.enclClass.type);
2288 result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym));
2289 }
2290 }
2291
2292 //where
2293 private boolean nonVirtualForPrivateAccess(Symbol sym) {
2294 boolean useVirtual = target.hasVirtualPrivateInvoke() &&
2295 !disableVirtualizedPrivateInvoke;
2296 return !useVirtual && ((sym.flags() & PRIVATE) != 0);
2297 }
2298
2299 public void visitSelect(JCFieldAccess tree) {
2300 Symbol sym = tree.sym;
2301
2302 if (tree.name == names._class) {
2303 code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
2304 result = items.makeStackItem(pt);
2305 return;
2306 }
2307
2308 Symbol ssym = TreeInfo.symbol(tree.selected);
2309
2310 // Are we selecting via super?
2311 boolean selectSuper =
2312 ssym != null && (ssym.kind == TYP || ssym.name == names._super);
2313
2314 // Are we accessing a member of the superclass in an access method
2315 // resulting from a qualified super?
2316 boolean accessSuper = isAccessSuper(env.enclMethod);
2317
2318 Item base = (selectSuper)
2319 ? items.makeSuperItem()
2320 : genExpr(tree.selected, tree.selected.type);
2321
2322 if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) {
2323 // We are seeing a variable that is constant but its selecting
2324 // expression is not.
2325 if ((sym.flags() & STATIC) != 0) {
2326 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2342 if ((sym.flags() & STATIC) != 0) {
2343 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2344 base = base.load();
2345 base.drop();
2346 result = items.makeStaticItem(sym);
2347 } else {
2348 base.load();
2349 if (sym == syms.lengthVar) {
2350 code.emitop0(arraylength);
2351 result = items.makeStackItem(syms.intType);
2352 } else {
2353 result = items.
2354 makeMemberItem(sym,
2355 nonVirtualForPrivateAccess(sym) ||
2356 selectSuper || accessSuper);
2357 }
2358 }
2359 }
2360 }
2361
2362 public boolean isInvokeDynamic(Symbol sym) {
2363 return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
2364 }
2365
2366 public void visitLiteral(JCLiteral tree) {
2367 if (tree.type.hasTag(BOT)) {
2368 code.emitop0(aconst_null);
2369 result = items.makeStackItem(tree.type);
2370 }
2371 else
2372 result = items.makeImmediateItem(tree.type, tree.value);
2373 }
2374
2375 public void visitLetExpr(LetExpr tree) {
2376 code.resolvePending();
2377
2378 int limit = code.nextreg;
2379 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
2380 try {
2381 genStats(tree.defs, env);
2398 /* ************************************************************************
2399 * main method
2400 *************************************************************************/
2401
2402 /** Generate code for a class definition.
2403 * @param env The attribution environment that belongs to the
2404 * outermost class containing this class definition.
2405 * We need this for resolving some additional symbols.
2406 * @param cdef The tree representing the class definition.
2407 * @return True if code is generated with no errors.
2408 */
2409 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2410 try {
2411 attrEnv = env;
2412 ClassSymbol c = cdef.sym;
2413 this.toplevel = env.toplevel;
2414 this.endPosTable = toplevel.endPositions;
2415 /* method normalizeDefs() can add references to external classes into the constant pool
2416 */
2417 cdef.defs = normalizeDefs(cdef.defs, c);
2418 generateReferencesToPrunedTree(c);
2419 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2420 localEnv.toplevel = env.toplevel;
2421 localEnv.enclClass = cdef;
2422
2423 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2424 genDef(l.head, localEnv);
2425 }
2426 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2427 log.error(cdef.pos(), Errors.LimitPool);
2428 nerrs++;
2429 }
2430 if (nerrs != 0) {
2431 // if errors, discard code
2432 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2433 if (l.head.hasTag(METHODDEF))
2434 ((JCMethodDecl) l.head).sym.code = null;
2435 }
2436 }
2437 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 protected Gen(Context context) {
103 context.put(genKey, this);
104
105 names = Names.instance(context);
106 log = Log.instance(context);
107 syms = Symtab.instance(context);
108 chk = Check.instance(context);
109 rs = Resolve.instance(context);
110 make = TreeMaker.instance(context);
111 target = Target.instance(context);
112 types = Types.instance(context);
113 concat = StringConcat.instance(context);
114
115 methodType = new MethodType(null, null, null, syms.methodClass);
116 accessDollar = names.
117 fromString("access" + target.syntheticNameChar());
118 lower = Lower.instance(context);
119 transValues = TransValues.instance(context);
120
121 Options options = Options.instance(context);
122 lineDebugInfo =
123 options.isUnset(G_CUSTOM) ||
124 options.isSet(G_CUSTOM, "lines");
125 varDebugInfo =
126 options.isUnset(G_CUSTOM)
127 ? options.isSet(G)
128 : options.isSet(G_CUSTOM, "vars");
129 genCrt = options.isSet(XJCOV);
130 debugCode = options.isSet("debug.code");
131 disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
132 poolWriter = new PoolWriter(types, names);
133
134 // ignore cldc because we cannot have both stackmap formats
135 this.stackMap = StackMapFormat.JSR202;
136 annotate = Annotate.instance(context);
137 Source source = Source.instance(context);
138 allowPrimitiveClasses = Source.Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
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
149 /** Code buffer, set by genMethod.
150 */
151 private Code code;
152
153 /** Items structure, set by genMethod.
154 */
155 private Items items;
156
157 /** Environment for symbol lookup, set by genClass
158 */
162 */
163 private JCCompilationUnit toplevel;
164
165 /** The number of code-gen errors in this class.
166 */
167 private int nerrs = 0;
168
169 /** An object containing mappings of syntax trees to their
170 * ending source positions.
171 */
172 EndPosTable endPosTable;
173
174 boolean inCondSwitchExpression;
175 Chain switchExpressionTrueChain;
176 Chain switchExpressionFalseChain;
177 List<LocalItem> stackBeforeSwitchExpression;
178 LocalItem switchResult;
179 Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of();
180 ListBuffer<int[]> patternMatchingInvocationRanges;
181
182 boolean allowPrimitiveClasses;
183
184 /** Generate code to load an integer constant.
185 * @param n The integer to be loaded.
186 */
187 void loadIntConst(int n) {
188 items.makeImmediateItem(syms.intType, n).load();
189 }
190
191 /** The opcode that loads a zero constant of a given type code.
192 * @param tc The given type code (@see ByteCode).
193 */
194 public static int zero(int tc) {
195 switch(tc) {
196 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
197 return iconst_0;
198 case LONGcode:
199 return lconst_0;
200 case FLOATcode:
201 return fconst_0;
202 case DOUBLEcode:
203 return dconst_0;
207 }
208
209 /** The opcode that loads a one constant of a given type code.
210 * @param tc The given type code (@see ByteCode).
211 */
212 public static int one(int tc) {
213 return zero(tc) + 1;
214 }
215
216 /** Generate code to load -1 of the given type code (either int or long).
217 * @param tc The given type code (@see ByteCode).
218 */
219 void emitMinusOne(int tc) {
220 if (tc == LONGcode) {
221 items.makeImmediateItem(syms.longType, Long.valueOf(-1)).load();
222 } else {
223 code.emitop0(iconst_m1);
224 }
225 }
226
227 /** Insert a reference to given type in the constant pool,
228 * checking for an array with too many dimensions;
229 * return the reference's index.
230 * @param type The type for which a reference is inserted.
231 */
232 int makeRef(DiagnosticPosition pos, Type type, boolean emitQtype) {
233 checkDimension(pos, type);
234 if (emitQtype) {
235 return poolWriter.putClass(new ConstantPoolQType(type, types));
236 } else {
237 return poolWriter.putClass(type);
238 }
239 }
240
241 /** Insert a reference to given type in the constant pool,
242 * checking for an array with too many dimensions;
243 * return the reference's index.
244 * @param type The type for which a reference is inserted.
245 */
246 int makeRef(DiagnosticPosition pos, Type type) {
247 return makeRef(pos, type, false);
248 }
249
250 /** Check if the given type is an array with too many dimensions.
251 */
252 private Type checkDimension(DiagnosticPosition pos, Type t) {
253 checkDimensionInternal(pos, t);
254 return t;
255 }
256
257 private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
258 switch (t.getTag()) {
259 case METHOD:
260 checkDimension(pos, t.getReturnType());
261 for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail)
262 checkDimension(pos, args.head);
263 break;
264 case ARRAY:
265 if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
266 log.error(pos, Errors.LimitDimensions);
267 nerrs++;
281 type,
282 env.enclMethod.sym);
283 code.newLocal(v);
284 return items.makeLocalItem(v);
285 }
286
287 /** Generate code to call a non-private method or constructor.
288 * @param pos Position to be used for error reporting.
289 * @param site The type of which the method is a member.
290 * @param name The method's name.
291 * @param argtypes The method's argument types.
292 * @param isStatic A flag that indicates whether we call a
293 * static or instance method.
294 */
295 void callMethod(DiagnosticPosition pos,
296 Type site, Name name, List<Type> argtypes,
297 boolean isStatic) {
298 Symbol msym = rs.
299 resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
300 if (isStatic) items.makeStaticItem(msym).invoke();
301 else items.makeMemberItem(msym, names.isInitOrVNew(name)).invoke();
302 }
303
304 /** Is the given method definition an access method
305 * resulting from a qualified super? This is signified by an odd
306 * access code.
307 */
308 private boolean isAccessSuper(JCMethodDecl enclMethod) {
309 return
310 (enclMethod.mods.flags & SYNTHETIC) != 0 &&
311 isOddAccessName(enclMethod.name);
312 }
313
314 /** Does given name start with "access$" and end in an odd digit?
315 */
316 private boolean isOddAccessName(Name name) {
317 return
318 name.startsWith(accessDollar) &&
319 (name.getByteAt(name.getByteLength() - 1) & 1) == 1;
320 }
321
504 /** Check a constant value and report if it is a string that is
505 * too large.
506 */
507 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
508 if (nerrs != 0 || // only complain about a long string once
509 constValue == null ||
510 !(constValue instanceof String str) ||
511 str.length() < PoolWriter.MAX_STRING_LENGTH)
512 return;
513 log.error(pos, Errors.LimitString);
514 nerrs++;
515 }
516
517 /** Insert instance initializer code into initial constructor.
518 * @param md The tree potentially representing a
519 * constructor's definition.
520 * @param initCode The list of instance initializer statements.
521 * @param initTAs Type annotations from the initializer expression.
522 */
523 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
524 if (names.isInitOrVNew(md.name) && TreeInfo.isInitialConstructor(md)) {
525 // We are seeing a constructor that does not call another
526 // constructor of the same class.
527 List<JCStatement> stats = md.body.stats;
528 ListBuffer<JCStatement> newstats = new ListBuffer<>();
529
530 if (stats.nonEmpty()) {
531 // Copy initializers of synthetic variables generated in
532 // the translation of inner classes.
533 while (TreeInfo.isSyntheticInit(stats.head)) {
534 newstats.append(stats.head);
535 stats = stats.tail;
536 }
537 // Copy superclass constructor call
538 newstats.append(stats.head);
539 stats = stats.tail;
540 // Copy remaining synthetic initializers.
541 while (stats.nonEmpty() &&
542 TreeInfo.isSyntheticInit(stats.head)) {
543 newstats.append(stats.head);
544 stats = stats.tail;
907 // is the method's return type.
908 this.pt = tree.sym.erasure(types).getReturnType();
909
910 checkDimension(tree.pos(), tree.sym.erasure(types));
911 genMethod(tree, localEnv, false);
912 }
913 //where
914 /** Generate code for a method.
915 * @param tree The tree representing the method definition.
916 * @param env The environment current for the method body.
917 * @param fatcode A flag that indicates whether all jumps are
918 * within 32K. We first invoke this method under
919 * the assumption that fatcode == false, i.e. all
920 * jumps are within 32K. If this fails, fatcode
921 * is set to true and we try again.
922 */
923 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
924 MethodSymbol meth = tree.sym;
925 int extras = 0;
926 // Count up extra parameters
927 if (meth.isInitOrVNew()) {
928 extras++;
929 if (meth.enclClass().isInner() &&
930 !meth.enclClass().isStatic()) {
931 extras++;
932 }
933 } else if ((tree.mods.flags & STATIC) == 0) {
934 extras++;
935 }
936 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
937 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras >
938 ClassFile.MAX_PARAMETERS) {
939 log.error(tree.pos(), Errors.LimitParameters);
940 nerrs++;
941 }
942
943 else if (tree.body != null) {
944 // Create a new code structure and initialize it.
945 int startpcCrt = initCode(tree, env, fatcode);
946
947 try {
948 genStat(tree.body, env);
949 } catch (CodeSizeOverflow e) {
950 // Failed due to code limit, try again with jsr/ret
951 startpcCrt = initCode(tree, env, fatcode);
952 genStat(tree.body, env);
953 }
954
955 if (code.state.stacksize != 0) {
956 log.error(tree.body.pos(), Errors.StackSimError(tree.sym));
957 throw new AssertionError();
958 }
959
960 // If last statement could complete normally, insert a
961 // return at the end.
962 if (code.isAlive()) {
963 code.statBegin(TreeInfo.endPos(tree.body));
964 if (env.enclMethod == null ||
965 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
966 code.emitop0(return_);
967 } else if (env.enclMethod.sym.isValueObjectFactory()) {
968 items.makeLocalItem(env.enclMethod.factoryProduct).load();
969 code.emitop0(areturn);
970 } else {
971 // sometime dead code seems alive (4415991);
972 // generate a small loop instead
973 int startpc = code.entryPoint();
974 CondItem c = items.makeCondItem(goto_);
975 code.resolve(c.jumpTrue(), startpc);
976 }
977 }
978 if (genCrt)
979 code.crt.put(tree.body,
980 CRT_BLOCK,
981 startpcCrt,
982 code.curCP());
983
984 code.endScopes(0);
985
986 // If we exceeded limits, panic
987 if (code.checkLimits(tree.pos(), log)) {
988 nerrs++;
989 return;
1004
1005 // Fill in type annotation positions for exception parameters
1006 code.fillExceptionParameterPositions();
1007 }
1008 }
1009
1010 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1011 MethodSymbol meth = tree.sym;
1012
1013 // Create a new code structure.
1014 meth.code = code = new Code(meth,
1015 fatcode,
1016 lineDebugInfo ? toplevel.lineMap : null,
1017 varDebugInfo,
1018 stackMap,
1019 debugCode,
1020 genCrt ? new CRTable(tree, env.toplevel.endPositions)
1021 : null,
1022 syms,
1023 types,
1024 poolWriter,
1025 allowPrimitiveClasses);
1026 items = new Items(poolWriter, code, syms, types);
1027 if (code.debugCode) {
1028 System.err.println(meth + " for body " + tree);
1029 }
1030
1031 // If method is not static, create a new local variable address
1032 // for `this'.
1033 if ((tree.mods.flags & STATIC) == 0) {
1034 Type selfType = meth.owner.type;
1035 if (meth.isInitOrVNew() && selfType != syms.objectType)
1036 selfType = UninitializedType.uninitializedThis(selfType);
1037 code.setDefined(
1038 code.newLocal(
1039 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1040 }
1041
1042 // Mark all parameters as defined from the beginning of
1043 // the method.
1044 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1045 checkDimension(l.head.pos(), l.head.sym.type);
1046 code.setDefined(code.newLocal(l.head.sym));
1047 }
1048
1049 // Get ready to generate code for method body.
1050 int startpcCrt = genCrt ? code.curCP() : 0;
1051 code.entryPoint();
1052
1053 // Suppress initial stackmap
1054 code.pendingStackMap = false;
1055
1056 return startpcCrt;
1057 }
1058
1059 public void visitVarDef(JCVariableDecl tree) {
1060 VarSymbol v = tree.sym;
1061 if (tree.init != null) {
1062 checkStringConstant(tree.init.pos(), v.getConstValue());
1063 if (v.getConstValue() == null || varDebugInfo) {
1064 Assert.check(code.isStatementStart());
1065 code.newLocal(v);
1066 genExpr(tree.init, v.erasure(types)).load();
1067 items.makeLocalItem(v).store();
1068 Assert.check(code.isStatementStart());
1069 }
1070 } else {
1071 code.newLocal(v);
1072 }
1073 checkDimension(tree.pos(), v.type);
1074 Type localType = v.erasure(types);
1075 if (localType.requiresPreload(env.enclClass.sym)) {
1076 poolWriter.enterPreloadClass((ClassSymbol) localType.tsym);
1077 }
1078 }
1079
1080 public void visitSkip(JCSkip tree) {
1081 }
1082
1083 public void visitBlock(JCBlock tree) {
1084 if (tree.patternMatchingCatch != null) {
1085 Set<JCMethodInvocation> prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch;
1086 ListBuffer<int[]> prevRanges = patternMatchingInvocationRanges;
1087 State startState = code.state.dup();
1088 try {
1089 invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle();
1090 patternMatchingInvocationRanges = new ListBuffer<>();
1091 doVisitBlock(tree);
1092 } finally {
1093 Chain skipCatch = code.branch(goto_);
1094 JCCatch handler = tree.patternMatchingCatch.handler();
1095 code.entryPoint(startState, handler.param.sym.type);
1096 genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList());
1097 code.resolve(skipCatch);
1106 private void doVisitBlock(JCBlock tree) {
1107 int limit = code.nextreg;
1108 Env<GenContext> localEnv = env.dup(tree, new GenContext());
1109 genStats(tree.stats, localEnv);
1110 // End the scope of all block-local variables in variable info.
1111 if (!env.tree.hasTag(METHODDEF)) {
1112 code.statBegin(tree.endpos);
1113 code.endScopes(limit);
1114 code.pendingStatPos = Position.NOPOS;
1115 }
1116 }
1117
1118 public void visitDoLoop(JCDoWhileLoop tree) {
1119 genLoop(tree, tree.body, tree.cond, List.nil(), false);
1120 }
1121
1122 public void visitWhileLoop(JCWhileLoop tree) {
1123 genLoop(tree, tree.body, tree.cond, List.nil(), true);
1124 }
1125
1126 public void visitWithField(JCWithField tree) {
1127 switch(tree.field.getTag()) {
1128 case IDENT:
1129 Symbol sym = ((JCIdent) tree.field).sym;
1130 items.makeThisItem().load();
1131 genExpr(tree.value, tree.field.type).load();
1132 sym = types.binaryQualifier(sym, env.enclClass.type);
1133 code.emitop2(withfield, sym, PoolWriter::putMember);
1134 result = items.makeStackItem(tree.type);
1135 break;
1136 case SELECT:
1137 JCFieldAccess fieldAccess = (JCFieldAccess) tree.field;
1138 sym = TreeInfo.symbol(fieldAccess);
1139 // JDK-8207332: To maintain the order of side effects, must compute value ahead of field
1140 genExpr(tree.value, tree.field.type).load();
1141 genExpr(fieldAccess.selected, fieldAccess.selected.type).load();
1142 if (Code.width(tree.field.type) == 2) {
1143 code.emitop0(dup_x2);
1144 code.emitop0(pop);
1145 } else {
1146 code.emitop0(swap);
1147 }
1148 sym = types.binaryQualifier(sym, fieldAccess.selected.type);
1149 code.emitop2(withfield, sym, PoolWriter::putMember);
1150 result = items.makeStackItem(tree.type);
1151 break;
1152 default:
1153 Assert.check(false);
1154 }
1155 }
1156
1157 public void visitForLoop(JCForLoop tree) {
1158 int limit = code.nextreg;
1159 genStats(tree.init, env);
1160 genLoop(tree, tree.body, tree.cond, tree.step, true);
1161 code.endScopes(limit);
1162 }
1163 //where
1164 /** Generate code for a loop.
1165 * @param loop The tree representing the loop.
1166 * @param body The loop's body.
1167 * @param cond The loop's controlling condition.
1168 * @param step "Step" statements to be inserted at end of
1169 * each iteration.
1170 * @param testFirst True if the loop test belongs before the body.
1171 */
1172 private void genLoop(JCStatement loop,
1173 JCStatement body,
1174 JCExpression cond,
1175 List<JCExpressionStatement> step,
1176 boolean testFirst) {
2052 result = arr;
2053 } else {
2054 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
2055 genExpr(l.head, syms.intType).load();
2056 }
2057 result = makeNewArray(tree.pos(), tree.type, tree.dims.length());
2058 }
2059 }
2060 //where
2061 /** Generate code to create an array with given element type and number
2062 * of dimensions.
2063 */
2064 Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
2065 Type elemtype = types.elemtype(type);
2066 if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) {
2067 log.error(pos, Errors.LimitDimensions);
2068 nerrs++;
2069 }
2070 int elemcode = Code.arraycode(elemtype);
2071 if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
2072 code.emitAnewarray(makeRef(pos, elemtype, elemtype.isPrimitiveClass()), type);
2073 } else if (elemcode == 1) {
2074 code.emitMultianewarray(ndims, makeRef(pos, type), type);
2075 } else {
2076 code.emitNewarray(elemcode, type);
2077 }
2078 return items.makeStackItem(type);
2079 }
2080
2081 public void visitParens(JCParens tree) {
2082 result = genExpr(tree.expr, tree.expr.type);
2083 }
2084
2085 public void visitAssign(JCAssign tree) {
2086 Item l = genExpr(tree.lhs, tree.lhs.type);
2087 genExpr(tree.rhs, tree.lhs.type).load();
2088 if (tree.rhs.type.hasTag(BOT)) {
2089 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
2090 for "regarding a reference as having some other type in a manner that can be proved
2091 correct at compile time."
2092 */
2278 code.emitop0(opcode >> preShift);
2279 opcode = opcode & 0xFF;
2280 }
2281 }
2282 if (opcode >= ifeq && opcode <= if_acmpne ||
2283 opcode == if_acmp_null || opcode == if_acmp_nonnull) {
2284 return items.makeCondItem(opcode);
2285 } else {
2286 code.emitop0(opcode);
2287 return items.makeStackItem(optype.restype);
2288 }
2289 }
2290
2291 public void visitTypeCast(JCTypeCast tree) {
2292 result = genExpr(tree.expr, tree.clazz.type).load();
2293 setTypeAnnotationPositions(tree.pos);
2294 // Additional code is only needed if we cast to a reference type
2295 // which is not statically a supertype of the expression's type.
2296 // For basic types, the coerce(...) in genExpr(...) will do
2297 // the conversion.
2298 // primitive reference conversion is a nop when we bifurcate the primitive class, as the VM sees a subtyping relationship.
2299 if (!tree.clazz.type.isPrimitive() &&
2300 !types.isSameType(tree.expr.type, tree.clazz.type) &&
2301 (!tree.clazz.type.isReferenceProjection() || !types.isSameType(tree.clazz.type.valueProjection(), tree.expr.type) || true) &&
2302 !types.isSubtype(tree.expr.type, tree.clazz.type)) {
2303 checkDimension(tree.pos(), tree.clazz.type);
2304 if (tree.clazz.type.isPrimitiveClass()) {
2305 code.emitop2(checkcast, new ConstantPoolQType(tree.clazz.type, types), PoolWriter::putClass);
2306 } else {
2307 code.emitop2(checkcast, tree.clazz.type, PoolWriter::putClass);
2308 }
2309
2310 }
2311 }
2312
2313 public void visitWildcard(JCWildcard tree) {
2314 throw new AssertionError(this.getClass().getName());
2315 }
2316
2317 public void visitTypeTest(JCInstanceOf tree) {
2318 genExpr(tree.expr, tree.expr.type).load();
2319 setTypeAnnotationPositions(tree.pos);
2320 code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
2321 result = items.makeStackItem(syms.booleanType);
2322 }
2323
2324 public void visitIndexed(JCArrayAccess tree) {
2325 genExpr(tree.indexed, tree.indexed.type).load();
2326 genExpr(tree.index, syms.intType).load();
2327 result = items.makeIndexedItem(tree.type);
2328 }
2329
2351 sym = types.binaryQualifier(sym, env.enclClass.type);
2352 result = items.makeStaticItem(sym);
2353 } else {
2354 items.makeThisItem().load();
2355 sym = types.binaryQualifier(sym, env.enclClass.type);
2356 result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym));
2357 }
2358 }
2359
2360 //where
2361 private boolean nonVirtualForPrivateAccess(Symbol sym) {
2362 boolean useVirtual = target.hasVirtualPrivateInvoke() &&
2363 !disableVirtualizedPrivateInvoke;
2364 return !useVirtual && ((sym.flags() & PRIVATE) != 0);
2365 }
2366
2367 public void visitSelect(JCFieldAccess tree) {
2368 Symbol sym = tree.sym;
2369
2370 if (tree.name == names._class) {
2371 code.emitLdc((LoadableConstant) tree.selected.type, makeRef(tree.pos(), tree.selected.type, tree.selected.type.isPrimitiveClass()));
2372 result = items.makeStackItem(pt);
2373 return;
2374 }
2375
2376 Symbol ssym = TreeInfo.symbol(tree.selected);
2377
2378 // Are we selecting via super?
2379 boolean selectSuper =
2380 ssym != null && (ssym.kind == TYP || ssym.name == names._super);
2381
2382 // Are we accessing a member of the superclass in an access method
2383 // resulting from a qualified super?
2384 boolean accessSuper = isAccessSuper(env.enclMethod);
2385
2386 Item base = (selectSuper)
2387 ? items.makeSuperItem()
2388 : genExpr(tree.selected, tree.selected.type);
2389
2390 if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) {
2391 // We are seeing a variable that is constant but its selecting
2392 // expression is not.
2393 if ((sym.flags() & STATIC) != 0) {
2394 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2410 if ((sym.flags() & STATIC) != 0) {
2411 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2412 base = base.load();
2413 base.drop();
2414 result = items.makeStaticItem(sym);
2415 } else {
2416 base.load();
2417 if (sym == syms.lengthVar) {
2418 code.emitop0(arraylength);
2419 result = items.makeStackItem(syms.intType);
2420 } else {
2421 result = items.
2422 makeMemberItem(sym,
2423 nonVirtualForPrivateAccess(sym) ||
2424 selectSuper || accessSuper);
2425 }
2426 }
2427 }
2428 }
2429
2430 public void visitDefaultValue(JCDefaultValue tree) {
2431 if (tree.type.isValueClass()) {
2432 code.emitop2(aconst_init, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
2433 } else if (tree.type.isReference()) {
2434 code.emitop0(aconst_null);
2435 } else {
2436 code.emitop0(zero(Code.typecode(tree.type)));
2437 }
2438 result = items.makeStackItem(tree.type);
2439 return;
2440 }
2441
2442 public boolean isInvokeDynamic(Symbol sym) {
2443 return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
2444 }
2445
2446 public void visitLiteral(JCLiteral tree) {
2447 if (tree.type.hasTag(BOT)) {
2448 code.emitop0(aconst_null);
2449 result = items.makeStackItem(tree.type);
2450 }
2451 else
2452 result = items.makeImmediateItem(tree.type, tree.value);
2453 }
2454
2455 public void visitLetExpr(LetExpr tree) {
2456 code.resolvePending();
2457
2458 int limit = code.nextreg;
2459 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
2460 try {
2461 genStats(tree.defs, env);
2478 /* ************************************************************************
2479 * main method
2480 *************************************************************************/
2481
2482 /** Generate code for a class definition.
2483 * @param env The attribution environment that belongs to the
2484 * outermost class containing this class definition.
2485 * We need this for resolving some additional symbols.
2486 * @param cdef The tree representing the class definition.
2487 * @return True if code is generated with no errors.
2488 */
2489 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2490 try {
2491 attrEnv = env;
2492 ClassSymbol c = cdef.sym;
2493 this.toplevel = env.toplevel;
2494 this.endPosTable = toplevel.endPositions;
2495 /* method normalizeDefs() can add references to external classes into the constant pool
2496 */
2497 cdef.defs = normalizeDefs(cdef.defs, c);
2498 cdef = transValues.translateTopLevelClass(cdef, make);
2499 generateReferencesToPrunedTree(c);
2500 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2501 localEnv.toplevel = env.toplevel;
2502 localEnv.enclClass = cdef;
2503
2504 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2505 genDef(l.head, localEnv);
2506 }
2507 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2508 log.error(cdef.pos(), Errors.LimitPool);
2509 nerrs++;
2510 }
2511 if (nerrs != 0) {
2512 // if errors, discard code
2513 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2514 if (l.head.hasTag(METHODDEF))
2515 ((JCMethodDecl) l.head).sym.code = null;
2516 }
2517 }
2518 cdef.defs = List.nil(); // discard trees
|