< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java

Print this page

  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
< prev index next >