Gen.java revision 3528:5538ba41cb97
1205821Sedwin/* 2205872Sedwin * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 3205872Sedwin * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4205821Sedwin * 5205821Sedwin * This code is free software; you can redistribute it and/or modify it 6205821Sedwin * under the terms of the GNU General Public License version 2 only, as 7205821Sedwin * published by the Free Software Foundation. Oracle designates this 8205821Sedwin * particular file as subject to the "Classpath" exception as provided 9205821Sedwin * by Oracle in the LICENSE file that accompanied this code. 10205821Sedwin * 11205821Sedwin * This code is distributed in the hope that it will be useful, but WITHOUT 12205821Sedwin * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13251647Sgrog * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14205821Sedwin * version 2 for more details (a copy is included in the LICENSE file that 15205821Sedwin * accompanied this code). 16205821Sedwin * 17205821Sedwin * You should have received a copy of the GNU General Public License version 18205821Sedwin * 2 along with this work; if not, write to the Free Software Foundation, 19205821Sedwin * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20205821Sedwin * 21205821Sedwin * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22205821Sedwin * or visit www.oracle.com if you need additional information or have any 23205821Sedwin * questions. 24205821Sedwin */ 25251647Sgrog 26205821Sedwinpackage com.sun.tools.javac.jvm; 27205821Sedwin 28205821Sedwinimport com.sun.tools.javac.util.*; 29205821Sedwinimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 30205821Sedwinimport com.sun.tools.javac.util.List; 31205821Sedwinimport com.sun.tools.javac.code.*; 32205821Sedwinimport com.sun.tools.javac.code.Attribute.TypeCompound; 33205821Sedwinimport com.sun.tools.javac.code.Symbol.VarSymbol; 34205821Sedwinimport com.sun.tools.javac.comp.*; 35205821Sedwinimport com.sun.tools.javac.tree.*; 36205821Sedwin 37205821Sedwinimport com.sun.tools.javac.code.Symbol.*; 38205821Sedwinimport com.sun.tools.javac.code.Type.*; 39205821Sedwinimport com.sun.tools.javac.jvm.Code.*; 40205821Sedwinimport com.sun.tools.javac.jvm.Items.*; 41205821Sedwinimport com.sun.tools.javac.main.Option; 42205821Sedwinimport com.sun.tools.javac.tree.EndPosTable; 43205821Sedwinimport com.sun.tools.javac.tree.JCTree.*; 44205821Sedwin 45205821Sedwinimport static com.sun.tools.javac.code.Flags.*; 46205821Sedwinimport static com.sun.tools.javac.code.Kinds.Kind.*; 47205821Sedwinimport static com.sun.tools.javac.code.TypeTag.*; 48205821Sedwinimport static com.sun.tools.javac.jvm.ByteCodes.*; 49205821Sedwinimport static com.sun.tools.javac.jvm.CRTFlags.*; 50205821Sedwinimport static com.sun.tools.javac.main.Option.*; 51205821Sedwinimport static com.sun.tools.javac.tree.JCTree.Tag.*; 52205821Sedwin 53205821Sedwin/** This pass maps flat Java (i.e. without inner classes) to bytecodes. 54205821Sedwin * 55205821Sedwin * <p><b>This is NOT part of any supported API. 56205821Sedwin * If you write code that depends on this, you do so at your own risk. 57205821Sedwin * This code and its internal interfaces are subject to change or 58205821Sedwin * deletion without notice.</b> 59205821Sedwin */ 60205821Sedwinpublic class Gen extends JCTree.Visitor { 61205821Sedwin protected static final Context.Key<Gen> genKey = new Context.Key<>(); 62205821Sedwin 63205821Sedwin private final Log log; 64205821Sedwin private final Symtab syms; 65205821Sedwin private final Check chk; 66205821Sedwin private final Resolve rs; 67205821Sedwin private final TreeMaker make; 68205821Sedwin private final Names names; 69205821Sedwin private final Target target; 70205821Sedwin private Name accessDollar; 71205821Sedwin private final Types types; 72205821Sedwin private final Lower lower; 73205821Sedwin private final Flow flow; 74205821Sedwin private final Annotate annotate; 75205821Sedwin private final StringConcat concat; 76205821Sedwin 77205821Sedwin /** Format of stackmap tables to be generated. */ 78205821Sedwin private final Code.StackMapFormat stackMap; 79205821Sedwin 80205821Sedwin /** A type that serves as the expected type for all method expressions. 81205821Sedwin */ 82205821Sedwin private final Type methodType; 83205821Sedwin 84205821Sedwin /** 85205821Sedwin * Are we presently traversing a let expression ? Yes if depth != 0 86205821Sedwin */ 87205821Sedwin private int letExprDepth; 88205821Sedwin 89205821Sedwin public static Gen instance(Context context) { 90205821Sedwin Gen instance = context.get(genKey); 91205821Sedwin if (instance == null) 92205821Sedwin instance = new Gen(context); 93205821Sedwin return instance; 94205821Sedwin } 95205821Sedwin 96205821Sedwin /** Constant pool, reset by genClass. 97205821Sedwin */ 98205821Sedwin private Pool pool; 99205821Sedwin 100205821Sedwin protected Gen(Context context) { 101205821Sedwin context.put(genKey, this); 102205821Sedwin 103205821Sedwin names = Names.instance(context); 104205821Sedwin log = Log.instance(context); 105205821Sedwin syms = Symtab.instance(context); 106205821Sedwin chk = Check.instance(context); 107205821Sedwin rs = Resolve.instance(context); 108205821Sedwin make = TreeMaker.instance(context); 109205821Sedwin target = Target.instance(context); 110205821Sedwin types = Types.instance(context); 111205821Sedwin concat = StringConcat.instance(context); 112205821Sedwin 113205821Sedwin methodType = new MethodType(null, null, null, syms.methodClass); 114205821Sedwin accessDollar = names. 115205821Sedwin fromString("access" + target.syntheticNameChar()); 116205821Sedwin flow = Flow.instance(context); 117205821Sedwin lower = Lower.instance(context); 118205821Sedwin 119205821Sedwin Options options = Options.instance(context); 120205821Sedwin lineDebugInfo = 121205821Sedwin options.isUnset(G_CUSTOM) || 122205821Sedwin options.isSet(G_CUSTOM, "lines"); 123205821Sedwin varDebugInfo = 124205821Sedwin options.isUnset(G_CUSTOM) 125205821Sedwin ? options.isSet(G) 126205821Sedwin : options.isSet(G_CUSTOM, "vars"); 127205821Sedwin genCrt = options.isSet(XJCOV); 128205821Sedwin debugCode = options.isSet("debug.code"); 129205821Sedwin allowBetterNullChecks = target.hasObjects(); 130205821Sedwin pool = new Pool(types); 131205821Sedwin 132205821Sedwin // ignore cldc because we cannot have both stackmap formats 133205821Sedwin this.stackMap = StackMapFormat.JSR202; 134205821Sedwin annotate = Annotate.instance(context); 135205821Sedwin } 136205821Sedwin 137205821Sedwin /** Switches 138205821Sedwin */ 139205821Sedwin private final boolean lineDebugInfo; 140205821Sedwin private final boolean varDebugInfo; 141205821Sedwin private final boolean genCrt; 142205821Sedwin private final boolean debugCode; 143205821Sedwin private final boolean allowBetterNullChecks; 144205821Sedwin 145205821Sedwin /** Code buffer, set by genMethod. 146205821Sedwin */ 147205821Sedwin private Code code; 148205821Sedwin 149205821Sedwin /** Items structure, set by genMethod. 150205821Sedwin */ 151205821Sedwin private Items items; 152205821Sedwin 153205821Sedwin /** Environment for symbol lookup, set by genClass 154205821Sedwin */ 155205821Sedwin private Env<AttrContext> attrEnv; 156205821Sedwin 157205821Sedwin /** The top level tree. 158205821Sedwin */ 159205821Sedwin private JCCompilationUnit toplevel; 160205821Sedwin 161205821Sedwin /** The number of code-gen errors in this class. 162205821Sedwin */ 163205821Sedwin private int nerrs = 0; 164205821Sedwin 165205821Sedwin /** An object containing mappings of syntax trees to their 166205821Sedwin * ending source positions. 167205821Sedwin */ 168205821Sedwin EndPosTable endPosTable; 169205821Sedwin 170205821Sedwin /** Generate code to load an integer constant. 171205821Sedwin * @param n The integer to be loaded. 172205821Sedwin */ 173205821Sedwin void loadIntConst(int n) { 174205821Sedwin items.makeImmediateItem(syms.intType, n).load(); 175205821Sedwin } 176205821Sedwin 177205821Sedwin /** The opcode that loads a zero constant of a given type code. 178205821Sedwin * @param tc The given type code (@see ByteCode). 179205821Sedwin */ 180205821Sedwin public static int zero(int tc) { 181205821Sedwin switch(tc) { 182205821Sedwin case INTcode: case BYTEcode: case SHORTcode: case CHARcode: 183205821Sedwin return iconst_0; 184205821Sedwin case LONGcode: 185205821Sedwin return lconst_0; 186205821Sedwin case FLOATcode: 187205821Sedwin return fconst_0; 188205821Sedwin case DOUBLEcode: 189205821Sedwin return dconst_0; 190205821Sedwin default: 191205821Sedwin throw new AssertionError("zero"); 192205821Sedwin } 193205821Sedwin } 194205821Sedwin 195205821Sedwin /** The opcode that loads a one constant of a given type code. 196205821Sedwin * @param tc The given type code (@see ByteCode). 197205821Sedwin */ 198205821Sedwin public static int one(int tc) { 199205821Sedwin return zero(tc) + 1; 200205821Sedwin } 201205821Sedwin 202205821Sedwin /** Generate code to load -1 of the given type code (either int or long). 203205821Sedwin * @param tc The given type code (@see ByteCode). 204205821Sedwin */ 205205821Sedwin void emitMinusOne(int tc) { 206205821Sedwin if (tc == LONGcode) { 207205821Sedwin items.makeImmediateItem(syms.longType, Long.valueOf(-1)).load(); 208205821Sedwin } else { 209205821Sedwin code.emitop0(iconst_m1); 210205821Sedwin } 211205821Sedwin } 212205821Sedwin 213205821Sedwin /** Construct a symbol to reflect the qualifying type that should 214205821Sedwin * appear in the byte code as per JLS 13.1. 215205821Sedwin * 216205821Sedwin * For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except 217205821Sedwin * for those cases where we need to work around VM bugs). 218205821Sedwin * 219205821Sedwin * For {@literal target <= 1.1}: If qualified variable or method is defined in a 220205821Sedwin * non-accessible class, clone it with the qualifier class as owner. 221205821Sedwin * 222205821Sedwin * @param sym The accessed symbol 223205821Sedwin * @param site The qualifier's type. 224205821Sedwin */ 225205821Sedwin Symbol binaryQualifier(Symbol sym, Type site) { 226205821Sedwin 227205821Sedwin if (site.hasTag(ARRAY)) { 228205821Sedwin if (sym == syms.lengthVar || 229205821Sedwin sym.owner != syms.arrayClass) 230208829Sedwin return sym; 231205821Sedwin // array clone can be qualified by the array type in later targets 232205821Sedwin Symbol qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, 233205821Sedwin site, syms.noSymbol); 234208829Sedwin return sym.clone(qualifier); 235205821Sedwin } 236205821Sedwin 237205821Sedwin if (sym.owner == site.tsym || 238205821Sedwin (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) { 239205821Sedwin return sym; 240205821Sedwin } 241208829Sedwin 242208829Sedwin // leave alone methods inherited from Object 243205821Sedwin // JLS 13.1. 244205821Sedwin if (sym.owner == syms.objectType.tsym) 245205821Sedwin return sym; 246208829Sedwin 247205821Sedwin return sym.clone(site.tsym); 248205821Sedwin } 249205821Sedwin 250205821Sedwin /** Insert a reference to given type in the constant pool, 251205821Sedwin * checking for an array with too many dimensions; 252205821Sedwin * return the reference's index. 253205821Sedwin * @param type The type for which a reference is inserted. 254208829Sedwin */ 255208829Sedwin int makeRef(DiagnosticPosition pos, Type type) { 256208829Sedwin checkDimension(pos, type); 257205821Sedwin if (type.isAnnotated()) { 258205821Sedwin return pool.put((Object)type); 259205821Sedwin } else { 260205821Sedwin return pool.put(type.hasTag(CLASS) ? (Object)type.tsym : (Object)type); 261205821Sedwin } 262205821Sedwin } 263205821Sedwin 264205821Sedwin /** Check if the given type is an array with too many dimensions. 265205821Sedwin */ 266205821Sedwin private void checkDimension(DiagnosticPosition pos, Type t) { 267205821Sedwin switch (t.getTag()) { 268205821Sedwin case METHOD: 269208829Sedwin checkDimension(pos, t.getReturnType()); 270205821Sedwin for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail) 271205821Sedwin checkDimension(pos, args.head); 272205821Sedwin break; 273208829Sedwin case ARRAY: 274205821Sedwin if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) { 275205821Sedwin log.error(pos, "limit.dimensions"); 276205821Sedwin nerrs++; 277205821Sedwin } 278205821Sedwin break; 279205821Sedwin default: 280208829Sedwin break; 281208829Sedwin } 282205821Sedwin } 283205821Sedwin 284205821Sedwin /** Create a tempory variable. 285208829Sedwin * @param type The variable's type. 286205821Sedwin */ 287205821Sedwin LocalItem makeTemp(Type type) { 288205821Sedwin VarSymbol v = new VarSymbol(Flags.SYNTHETIC, 289205821Sedwin names.empty, 290205821Sedwin type, 291205821Sedwin env.enclMethod.sym); 292205821Sedwin code.newLocal(v); 293208829Sedwin return items.makeLocalItem(v); 294208829Sedwin } 295208829Sedwin 296205821Sedwin /** Generate code to call a non-private method or constructor. 297205821Sedwin * @param pos Position to be used for error reporting. 298205821Sedwin * @param site The type of which the method is a member. 299205821Sedwin * @param name The method's name. 300205821Sedwin * @param argtypes The method's argument types. 301205821Sedwin * @param isStatic A flag that indicates whether we call a 302205821Sedwin * static or instance method. 303205821Sedwin */ 304205821Sedwin void callMethod(DiagnosticPosition pos, 305205821Sedwin Type site, Name name, List<Type> argtypes, 306205821Sedwin boolean isStatic) { 307205821Sedwin Symbol msym = rs. 308205821Sedwin resolveInternalMethod(pos, attrEnv, site, name, argtypes, null); 309205821Sedwin if (isStatic) items.makeStaticItem(msym).invoke(); 310205821Sedwin else items.makeMemberItem(msym, name == names.init).invoke(); 311205821Sedwin } 312205821Sedwin 313205821Sedwin /** Is the given method definition an access method 314205821Sedwin * resulting from a qualified super? This is signified by an odd 315205821Sedwin * access code. 316205821Sedwin */ 317205821Sedwin private boolean isAccessSuper(JCMethodDecl enclMethod) { 318205821Sedwin return 319205821Sedwin (enclMethod.mods.flags & SYNTHETIC) != 0 && 320205821Sedwin isOddAccessName(enclMethod.name); 321205821Sedwin } 322205821Sedwin 323205821Sedwin /** Does given name start with "access$" and end in an odd digit? 324205821Sedwin */ 325205821Sedwin private boolean isOddAccessName(Name name) { 326205821Sedwin return 327205821Sedwin name.startsWith(accessDollar) && 328205821Sedwin (name.getByteAt(name.getByteLength() - 1) & 1) == 1; 329205821Sedwin } 330205821Sedwin 331205821Sedwin/* ************************************************************************ 332205821Sedwin * Non-local exits 333205821Sedwin *************************************************************************/ 334205821Sedwin 335205821Sedwin /** Generate code to invoke the finalizer associated with given 336205821Sedwin * environment. 337205821Sedwin * Any calls to finalizers are appended to the environments `cont' chain. 338205821Sedwin * Mark beginning of gap in catch all range for finalizer. 339205821Sedwin */ 340205821Sedwin void genFinalizer(Env<GenContext> env) { 341205821Sedwin if (code.isAlive() && env.info.finalize != null) 342205821Sedwin env.info.finalize.gen(); 343205821Sedwin } 344205821Sedwin 345205821Sedwin /** Generate code to call all finalizers of structures aborted by 346205821Sedwin * a non-local 347205821Sedwin * exit. Return target environment of the non-local exit. 348205821Sedwin * @param target The tree representing the structure that's aborted 349205821Sedwin * @param env The environment current at the non-local exit. 350205821Sedwin */ 351205821Sedwin Env<GenContext> unwind(JCTree target, Env<GenContext> env) { 352205821Sedwin Env<GenContext> env1 = env; 353205821Sedwin while (true) { 354205821Sedwin genFinalizer(env1); 355205821Sedwin if (env1.tree == target) break; 356205821Sedwin env1 = env1.next; 357205821Sedwin } 358205821Sedwin return env1; 359205821Sedwin } 360205821Sedwin 361205821Sedwin /** Mark end of gap in catch-all range for finalizer. 362205821Sedwin * @param env the environment which might contain the finalizer 363205821Sedwin * (if it does, env.info.gaps != null). 364205821Sedwin */ 365205821Sedwin void endFinalizerGap(Env<GenContext> env) { 366205821Sedwin if (env.info.gaps != null && env.info.gaps.length() % 2 == 1) 367205821Sedwin env.info.gaps.append(code.curCP()); 368205821Sedwin } 369205821Sedwin 370205821Sedwin /** Mark end of all gaps in catch-all ranges for finalizers of environments 371205821Sedwin * lying between, and including to two environments. 372205821Sedwin * @param from the most deeply nested environment to mark 373205821Sedwin * @param to the least deeply nested environment to mark 374205821Sedwin */ 375205821Sedwin void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) { 376251647Sgrog Env<GenContext> last = null; 377205821Sedwin while (last != to) { 378205821Sedwin endFinalizerGap(from); 379205821Sedwin last = from; 380205821Sedwin from = from.next; 381205821Sedwin } 382205821Sedwin } 383205821Sedwin 384205821Sedwin /** Do any of the structures aborted by a non-local exit have 385205821Sedwin * finalizers that require an empty stack? 386205821Sedwin * @param target The tree representing the structure that's aborted 387205821Sedwin * @param env The environment current at the non-local exit. 388205821Sedwin */ 389205821Sedwin boolean hasFinally(JCTree target, Env<GenContext> env) { 390205821Sedwin while (env.tree != target) { 391205821Sedwin if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer()) 392205821Sedwin return true; 393205821Sedwin env = env.next; 394205821Sedwin } 395205821Sedwin return false; 396205821Sedwin } 397205821Sedwin 398205821Sedwin/* ************************************************************************ 399205821Sedwin * Normalizing class-members. 400205821Sedwin *************************************************************************/ 401205821Sedwin 402205821Sedwin /** Distribute member initializer code into constructors and {@code <clinit>} 403205821Sedwin * method. 404205821Sedwin * @param defs The list of class member declarations. 405205821Sedwin * @param c The enclosing class. 406205821Sedwin */ 407205821Sedwin List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) { 408205821Sedwin ListBuffer<JCStatement> initCode = new ListBuffer<>(); 409205821Sedwin ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>(); 410205821Sedwin ListBuffer<JCStatement> clinitCode = new ListBuffer<>(); 411205821Sedwin ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>(); 412205821Sedwin ListBuffer<JCTree> methodDefs = new ListBuffer<>(); 413205821Sedwin // Sort definitions into three listbuffers: 414205821Sedwin // - initCode for instance initializers 415205821Sedwin // - clinitCode for class initializers 416205821Sedwin // - methodDefs for method definitions 417205821Sedwin for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) { 418205821Sedwin JCTree def = l.head; 419205821Sedwin switch (def.getTag()) { 420205821Sedwin case BLOCK: 421205821Sedwin JCBlock block = (JCBlock)def; 422205821Sedwin if ((block.flags & STATIC) != 0) 423205821Sedwin clinitCode.append(block); 424205821Sedwin else if ((block.flags & SYNTHETIC) == 0) 425205821Sedwin initCode.append(block); 426205821Sedwin break; 427205821Sedwin case METHODDEF: 428205821Sedwin methodDefs.append(def); 429205821Sedwin break; 430205821Sedwin case VARDEF: 431205821Sedwin JCVariableDecl vdef = (JCVariableDecl) def; 432205821Sedwin VarSymbol sym = vdef.sym; 433205821Sedwin checkDimension(vdef.pos(), sym.type); 434205821Sedwin if (vdef.init != null) { 435205821Sedwin if ((sym.flags() & STATIC) == 0) { 436205821Sedwin // Always initialize instance variables. 437205821Sedwin JCStatement init = make.at(vdef.pos()). 438205821Sedwin Assignment(sym, vdef.init); 439205821Sedwin initCode.append(init); 440205821Sedwin endPosTable.replaceTree(vdef, init); 441205821Sedwin initTAs.addAll(getAndRemoveNonFieldTAs(sym)); 442205821Sedwin } else if (sym.getConstValue() == null) { 443205821Sedwin // Initialize class (static) variables only if 444205821Sedwin // they are not compile-time constants. 445205821Sedwin JCStatement init = make.at(vdef.pos). 446205821Sedwin Assignment(sym, vdef.init); 447205821Sedwin clinitCode.append(init); 448205821Sedwin endPosTable.replaceTree(vdef, init); 449 clinitTAs.addAll(getAndRemoveNonFieldTAs(sym)); 450 } else { 451 checkStringConstant(vdef.init.pos(), sym.getConstValue()); 452 /* if the init contains a reference to an external class, add it to the 453 * constant's pool 454 */ 455 vdef.init.accept(classReferenceVisitor); 456 } 457 } 458 break; 459 default: 460 Assert.error(); 461 } 462 } 463 // Insert any instance initializers into all constructors. 464 if (initCode.length() != 0) { 465 List<JCStatement> inits = initCode.toList(); 466 initTAs.addAll(c.getInitTypeAttributes()); 467 List<Attribute.TypeCompound> initTAlist = initTAs.toList(); 468 for (JCTree t : methodDefs) { 469 normalizeMethod((JCMethodDecl)t, inits, initTAlist); 470 } 471 } 472 // If there are class initializers, create a <clinit> method 473 // that contains them as its body. 474 if (clinitCode.length() != 0) { 475 MethodSymbol clinit = new MethodSymbol( 476 STATIC | (c.flags() & STRICTFP), 477 names.clinit, 478 new MethodType( 479 List.<Type>nil(), syms.voidType, 480 List.<Type>nil(), syms.methodClass), 481 c); 482 c.members().enter(clinit); 483 List<JCStatement> clinitStats = clinitCode.toList(); 484 JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats); 485 block.endpos = TreeInfo.endPos(clinitStats.last()); 486 methodDefs.append(make.MethodDef(clinit, block)); 487 488 if (!clinitTAs.isEmpty()) 489 clinit.appendUniqueTypeAttributes(clinitTAs.toList()); 490 if (!c.getClassInitTypeAttributes().isEmpty()) 491 clinit.appendUniqueTypeAttributes(c.getClassInitTypeAttributes()); 492 } 493 // Return all method definitions. 494 return methodDefs.toList(); 495 } 496 497 private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) { 498 List<TypeCompound> tas = sym.getRawTypeAttributes(); 499 ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>(); 500 ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>(); 501 for (TypeCompound ta : tas) { 502 Assert.check(ta.getPosition().type != TargetType.UNKNOWN); 503 if (ta.getPosition().type == TargetType.FIELD) { 504 fieldTAs.add(ta); 505 } else { 506 nonfieldTAs.add(ta); 507 } 508 } 509 sym.setTypeAttributes(fieldTAs.toList()); 510 return nonfieldTAs.toList(); 511 } 512 513 /** Check a constant value and report if it is a string that is 514 * too large. 515 */ 516 private void checkStringConstant(DiagnosticPosition pos, Object constValue) { 517 if (nerrs != 0 || // only complain about a long string once 518 constValue == null || 519 !(constValue instanceof String) || 520 ((String)constValue).length() < Pool.MAX_STRING_LENGTH) 521 return; 522 log.error(pos, "limit.string"); 523 nerrs++; 524 } 525 526 /** Insert instance initializer code into initial constructor. 527 * @param md The tree potentially representing a 528 * constructor's definition. 529 * @param initCode The list of instance initializer statements. 530 * @param initTAs Type annotations from the initializer expression. 531 */ 532 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) { 533 if (md.name == names.init && TreeInfo.isInitialConstructor(md)) { 534 // We are seeing a constructor that does not call another 535 // constructor of the same class. 536 List<JCStatement> stats = md.body.stats; 537 ListBuffer<JCStatement> newstats = new ListBuffer<>(); 538 539 if (stats.nonEmpty()) { 540 // Copy initializers of synthetic variables generated in 541 // the translation of inner classes. 542 while (TreeInfo.isSyntheticInit(stats.head)) { 543 newstats.append(stats.head); 544 stats = stats.tail; 545 } 546 // Copy superclass constructor call 547 newstats.append(stats.head); 548 stats = stats.tail; 549 // Copy remaining synthetic initializers. 550 while (stats.nonEmpty() && 551 TreeInfo.isSyntheticInit(stats.head)) { 552 newstats.append(stats.head); 553 stats = stats.tail; 554 } 555 // Now insert the initializer code. 556 newstats.appendList(initCode); 557 // And copy all remaining statements. 558 while (stats.nonEmpty()) { 559 newstats.append(stats.head); 560 stats = stats.tail; 561 } 562 } 563 md.body.stats = newstats.toList(); 564 if (md.body.endpos == Position.NOPOS) 565 md.body.endpos = TreeInfo.endPos(md.body.stats.last()); 566 567 md.sym.appendUniqueTypeAttributes(initTAs); 568 } 569 } 570 571/* ************************************************************************ 572 * Traversal methods 573 *************************************************************************/ 574 575 /** Visitor argument: The current environment. 576 */ 577 Env<GenContext> env; 578 579 /** Visitor argument: The expected type (prototype). 580 */ 581 Type pt; 582 583 /** Visitor result: The item representing the computed value. 584 */ 585 Item result; 586 587 /** Visitor method: generate code for a definition, catching and reporting 588 * any completion failures. 589 * @param tree The definition to be visited. 590 * @param env The environment current at the definition. 591 */ 592 public void genDef(JCTree tree, Env<GenContext> env) { 593 Env<GenContext> prevEnv = this.env; 594 try { 595 this.env = env; 596 tree.accept(this); 597 } catch (CompletionFailure ex) { 598 chk.completionError(tree.pos(), ex); 599 } finally { 600 this.env = prevEnv; 601 } 602 } 603 604 /** Derived visitor method: check whether CharacterRangeTable 605 * should be emitted, if so, put a new entry into CRTable 606 * and call method to generate bytecode. 607 * If not, just call method to generate bytecode. 608 * @see #genStat(JCTree, Env) 609 * 610 * @param tree The tree to be visited. 611 * @param env The environment to use. 612 * @param crtFlags The CharacterRangeTable flags 613 * indicating type of the entry. 614 */ 615 public void genStat(JCTree tree, Env<GenContext> env, int crtFlags) { 616 if (!genCrt) { 617 genStat(tree, env); 618 return; 619 } 620 int startpc = code.curCP(); 621 genStat(tree, env); 622 if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK; 623 code.crt.put(tree, crtFlags, startpc, code.curCP()); 624 } 625 626 /** Derived visitor method: generate code for a statement. 627 */ 628 public void genStat(JCTree tree, Env<GenContext> env) { 629 if (code.isAlive()) { 630 code.statBegin(tree.pos); 631 genDef(tree, env); 632 } else if (env.info.isSwitch && tree.hasTag(VARDEF)) { 633 // variables whose declarations are in a switch 634 // can be used even if the decl is unreachable. 635 code.newLocal(((JCVariableDecl) tree).sym); 636 } 637 } 638 639 /** Derived visitor method: check whether CharacterRangeTable 640 * should be emitted, if so, put a new entry into CRTable 641 * and call method to generate bytecode. 642 * If not, just call method to generate bytecode. 643 * @see #genStats(List, Env) 644 * 645 * @param trees The list of trees to be visited. 646 * @param env The environment to use. 647 * @param crtFlags The CharacterRangeTable flags 648 * indicating type of the entry. 649 */ 650 public void genStats(List<JCStatement> trees, Env<GenContext> env, int crtFlags) { 651 if (!genCrt) { 652 genStats(trees, env); 653 return; 654 } 655 if (trees.length() == 1) { // mark one statement with the flags 656 genStat(trees.head, env, crtFlags | CRT_STATEMENT); 657 } else { 658 int startpc = code.curCP(); 659 genStats(trees, env); 660 code.crt.put(trees, crtFlags, startpc, code.curCP()); 661 } 662 } 663 664 /** Derived visitor method: generate code for a list of statements. 665 */ 666 public void genStats(List<? extends JCTree> trees, Env<GenContext> env) { 667 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 668 genStat(l.head, env, CRT_STATEMENT); 669 } 670 671 /** Derived visitor method: check whether CharacterRangeTable 672 * should be emitted, if so, put a new entry into CRTable 673 * and call method to generate bytecode. 674 * If not, just call method to generate bytecode. 675 * @see #genCond(JCTree,boolean) 676 * 677 * @param tree The tree to be visited. 678 * @param crtFlags The CharacterRangeTable flags 679 * indicating type of the entry. 680 */ 681 public CondItem genCond(JCTree tree, int crtFlags) { 682 if (!genCrt) return genCond(tree, false); 683 int startpc = code.curCP(); 684 CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0); 685 code.crt.put(tree, crtFlags, startpc, code.curCP()); 686 return item; 687 } 688 689 /** Derived visitor method: generate code for a boolean 690 * expression in a control-flow context. 691 * @param _tree The expression to be visited. 692 * @param markBranches The flag to indicate that the condition is 693 * a flow controller so produced conditions 694 * should contain a proper tree to generate 695 * CharacterRangeTable branches for them. 696 */ 697 public CondItem genCond(JCTree _tree, boolean markBranches) { 698 JCTree inner_tree = TreeInfo.skipParens(_tree); 699 if (inner_tree.hasTag(CONDEXPR)) { 700 JCConditional tree = (JCConditional)inner_tree; 701 CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER); 702 if (cond.isTrue()) { 703 code.resolve(cond.trueJumps); 704 CondItem result = genCond(tree.truepart, CRT_FLOW_TARGET); 705 if (markBranches) result.tree = tree.truepart; 706 return result; 707 } 708 if (cond.isFalse()) { 709 code.resolve(cond.falseJumps); 710 CondItem result = genCond(tree.falsepart, CRT_FLOW_TARGET); 711 if (markBranches) result.tree = tree.falsepart; 712 return result; 713 } 714 Chain secondJumps = cond.jumpFalse(); 715 code.resolve(cond.trueJumps); 716 CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET); 717 if (markBranches) first.tree = tree.truepart; 718 Chain falseJumps = first.jumpFalse(); 719 code.resolve(first.trueJumps); 720 Chain trueJumps = code.branch(goto_); 721 code.resolve(secondJumps); 722 CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET); 723 CondItem result = items.makeCondItem(second.opcode, 724 Code.mergeChains(trueJumps, second.trueJumps), 725 Code.mergeChains(falseJumps, second.falseJumps)); 726 if (markBranches) result.tree = tree.falsepart; 727 return result; 728 } else { 729 CondItem result = genExpr(_tree, syms.booleanType).mkCond(); 730 if (markBranches) result.tree = _tree; 731 return result; 732 } 733 } 734 735 public Code getCode() { 736 return code; 737 } 738 739 public Items getItems() { 740 return items; 741 } 742 743 public Env<AttrContext> getAttrEnv() { 744 return attrEnv; 745 } 746 747 /** Visitor class for expressions which might be constant expressions. 748 * This class is a subset of TreeScanner. Intended to visit trees pruned by 749 * Lower as long as constant expressions looking for references to any 750 * ClassSymbol. Any such reference will be added to the constant pool so 751 * automated tools can detect class dependencies better. 752 */ 753 class ClassReferenceVisitor extends JCTree.Visitor { 754 755 @Override 756 public void visitTree(JCTree tree) {} 757 758 @Override 759 public void visitBinary(JCBinary tree) { 760 tree.lhs.accept(this); 761 tree.rhs.accept(this); 762 } 763 764 @Override 765 public void visitSelect(JCFieldAccess tree) { 766 if (tree.selected.type.hasTag(CLASS)) { 767 makeRef(tree.selected.pos(), tree.selected.type); 768 } 769 } 770 771 @Override 772 public void visitIdent(JCIdent tree) { 773 if (tree.sym.owner instanceof ClassSymbol) { 774 pool.put(tree.sym.owner); 775 } 776 } 777 778 @Override 779 public void visitConditional(JCConditional tree) { 780 tree.cond.accept(this); 781 tree.truepart.accept(this); 782 tree.falsepart.accept(this); 783 } 784 785 @Override 786 public void visitUnary(JCUnary tree) { 787 tree.arg.accept(this); 788 } 789 790 @Override 791 public void visitParens(JCParens tree) { 792 tree.expr.accept(this); 793 } 794 795 @Override 796 public void visitTypeCast(JCTypeCast tree) { 797 tree.expr.accept(this); 798 } 799 } 800 801 private ClassReferenceVisitor classReferenceVisitor = new ClassReferenceVisitor(); 802 803 /** Visitor method: generate code for an expression, catching and reporting 804 * any completion failures. 805 * @param tree The expression to be visited. 806 * @param pt The expression's expected type (proto-type). 807 */ 808 public Item genExpr(JCTree tree, Type pt) { 809 Type prevPt = this.pt; 810 try { 811 if (tree.type.constValue() != null) { 812 // Short circuit any expressions which are constants 813 tree.accept(classReferenceVisitor); 814 checkStringConstant(tree.pos(), tree.type.constValue()); 815 result = items.makeImmediateItem(tree.type, tree.type.constValue()); 816 } else { 817 this.pt = pt; 818 tree.accept(this); 819 } 820 return result.coerce(pt); 821 } catch (CompletionFailure ex) { 822 chk.completionError(tree.pos(), ex); 823 code.state.stacksize = 1; 824 return items.makeStackItem(pt); 825 } finally { 826 this.pt = prevPt; 827 } 828 } 829 830 /** Derived visitor method: generate code for a list of method arguments. 831 * @param trees The argument expressions to be visited. 832 * @param pts The expression's expected types (i.e. the formal parameter 833 * types of the invoked method). 834 */ 835 public void genArgs(List<JCExpression> trees, List<Type> pts) { 836 for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) { 837 genExpr(l.head, pts.head).load(); 838 pts = pts.tail; 839 } 840 // require lists be of same length 841 Assert.check(pts.isEmpty()); 842 } 843 844/* ************************************************************************ 845 * Visitor methods for statements and definitions 846 *************************************************************************/ 847 848 /** Thrown when the byte code size exceeds limit. 849 */ 850 public static class CodeSizeOverflow extends RuntimeException { 851 private static final long serialVersionUID = 0; 852 public CodeSizeOverflow() {} 853 } 854 855 public void visitMethodDef(JCMethodDecl tree) { 856 // Create a new local environment that points pack at method 857 // definition. 858 Env<GenContext> localEnv = env.dup(tree); 859 localEnv.enclMethod = tree; 860 // The expected type of every return statement in this method 861 // is the method's return type. 862 this.pt = tree.sym.erasure(types).getReturnType(); 863 864 checkDimension(tree.pos(), tree.sym.erasure(types)); 865 genMethod(tree, localEnv, false); 866 } 867//where 868 /** Generate code for a method. 869 * @param tree The tree representing the method definition. 870 * @param env The environment current for the method body. 871 * @param fatcode A flag that indicates whether all jumps are 872 * within 32K. We first invoke this method under 873 * the assumption that fatcode == false, i.e. all 874 * jumps are within 32K. If this fails, fatcode 875 * is set to true and we try again. 876 */ 877 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { 878 MethodSymbol meth = tree.sym; 879 int extras = 0; 880 // Count up extra parameters 881 if (meth.isConstructor()) { 882 extras++; 883 if (meth.enclClass().isInner() && 884 !meth.enclClass().isStatic()) { 885 extras++; 886 } 887 } else if ((tree.mods.flags & STATIC) == 0) { 888 extras++; 889 } 890 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG 891 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras > 892 ClassFile.MAX_PARAMETERS) { 893 log.error(tree.pos(), "limit.parameters"); 894 nerrs++; 895 } 896 897 else if (tree.body != null) { 898 // Create a new code structure and initialize it. 899 int startpcCrt = initCode(tree, env, fatcode); 900 901 try { 902 genStat(tree.body, env); 903 } catch (CodeSizeOverflow e) { 904 // Failed due to code limit, try again with jsr/ret 905 startpcCrt = initCode(tree, env, fatcode); 906 genStat(tree.body, env); 907 } 908 909 if (code.state.stacksize != 0) { 910 log.error(tree.body.pos(), "stack.sim.error", tree); 911 throw new AssertionError(); 912 } 913 914 // If last statement could complete normally, insert a 915 // return at the end. 916 if (code.isAlive()) { 917 code.statBegin(TreeInfo.endPos(tree.body)); 918 if (env.enclMethod == null || 919 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) { 920 code.emitop0(return_); 921 } else { 922 // sometime dead code seems alive (4415991); 923 // generate a small loop instead 924 int startpc = code.entryPoint(); 925 CondItem c = items.makeCondItem(goto_); 926 code.resolve(c.jumpTrue(), startpc); 927 } 928 } 929 if (genCrt) 930 code.crt.put(tree.body, 931 CRT_BLOCK, 932 startpcCrt, 933 code.curCP()); 934 935 code.endScopes(0); 936 937 // If we exceeded limits, panic 938 if (code.checkLimits(tree.pos(), log)) { 939 nerrs++; 940 return; 941 } 942 943 // If we generated short code but got a long jump, do it again 944 // with fatCode = true. 945 if (!fatcode && code.fatcode) genMethod(tree, env, true); 946 947 // Clean up 948 if(stackMap == StackMapFormat.JSR202) { 949 code.lastFrame = null; 950 code.frameBeforeLast = null; 951 } 952 953 // Compress exception table 954 code.compressCatchTable(); 955 956 // Fill in type annotation positions for exception parameters 957 code.fillExceptionParameterPositions(); 958 } 959 } 960 961 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { 962 MethodSymbol meth = tree.sym; 963 964 // Create a new code structure. 965 meth.code = code = new Code(meth, 966 fatcode, 967 lineDebugInfo ? toplevel.lineMap : null, 968 varDebugInfo, 969 stackMap, 970 debugCode, 971 genCrt ? new CRTable(tree, env.toplevel.endPositions) 972 : null, 973 syms, 974 types, 975 pool); 976 items = new Items(pool, code, syms, types); 977 if (code.debugCode) { 978 System.err.println(meth + " for body " + tree); 979 } 980 981 // If method is not static, create a new local variable address 982 // for `this'. 983 if ((tree.mods.flags & STATIC) == 0) { 984 Type selfType = meth.owner.type; 985 if (meth.isConstructor() && selfType != syms.objectType) 986 selfType = UninitializedType.uninitializedThis(selfType); 987 code.setDefined( 988 code.newLocal( 989 new VarSymbol(FINAL, names._this, selfType, meth.owner))); 990 } 991 992 // Mark all parameters as defined from the beginning of 993 // the method. 994 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 995 checkDimension(l.head.pos(), l.head.sym.type); 996 code.setDefined(code.newLocal(l.head.sym)); 997 } 998 999 // Get ready to generate code for method body. 1000 int startpcCrt = genCrt ? code.curCP() : 0; 1001 code.entryPoint(); 1002 1003 // Suppress initial stackmap 1004 code.pendingStackMap = false; 1005 1006 return startpcCrt; 1007 } 1008 1009 public void visitVarDef(JCVariableDecl tree) { 1010 VarSymbol v = tree.sym; 1011 code.newLocal(v); 1012 if (tree.init != null) { 1013 checkStringConstant(tree.init.pos(), v.getConstValue()); 1014 if (v.getConstValue() == null || varDebugInfo) { 1015 Assert.check(letExprDepth != 0 || code.state.stacksize == 0); 1016 genExpr(tree.init, v.erasure(types)).load(); 1017 items.makeLocalItem(v).store(); 1018 Assert.check(letExprDepth != 0 || code.state.stacksize == 0); 1019 } 1020 } 1021 checkDimension(tree.pos(), v.type); 1022 } 1023 1024 public void visitSkip(JCSkip tree) { 1025 } 1026 1027 public void visitBlock(JCBlock tree) { 1028 int limit = code.nextreg; 1029 Env<GenContext> localEnv = env.dup(tree, new GenContext()); 1030 genStats(tree.stats, localEnv); 1031 // End the scope of all block-local variables in variable info. 1032 if (!env.tree.hasTag(METHODDEF)) { 1033 code.statBegin(tree.endpos); 1034 code.endScopes(limit); 1035 code.pendingStatPos = Position.NOPOS; 1036 } 1037 } 1038 1039 public void visitDoLoop(JCDoWhileLoop tree) { 1040 genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), false); 1041 } 1042 1043 public void visitWhileLoop(JCWhileLoop tree) { 1044 genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), true); 1045 } 1046 1047 public void visitForLoop(JCForLoop tree) { 1048 int limit = code.nextreg; 1049 genStats(tree.init, env); 1050 genLoop(tree, tree.body, tree.cond, tree.step, true); 1051 code.endScopes(limit); 1052 } 1053 //where 1054 /** Generate code for a loop. 1055 * @param loop The tree representing the loop. 1056 * @param body The loop's body. 1057 * @param cond The loop's controling condition. 1058 * @param step "Step" statements to be inserted at end of 1059 * each iteration. 1060 * @param testFirst True if the loop test belongs before the body. 1061 */ 1062 private void genLoop(JCStatement loop, 1063 JCStatement body, 1064 JCExpression cond, 1065 List<JCExpressionStatement> step, 1066 boolean testFirst) { 1067 Env<GenContext> loopEnv = env.dup(loop, new GenContext()); 1068 int startpc = code.entryPoint(); 1069 if (testFirst) { //while or for loop 1070 CondItem c; 1071 if (cond != null) { 1072 code.statBegin(cond.pos); 1073 Assert.check(code.state.stacksize == 0); 1074 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); 1075 } else { 1076 c = items.makeCondItem(goto_); 1077 } 1078 Chain loopDone = c.jumpFalse(); 1079 code.resolve(c.trueJumps); 1080 Assert.check(code.state.stacksize == 0); 1081 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); 1082 code.resolve(loopEnv.info.cont); 1083 genStats(step, loopEnv); 1084 code.resolve(code.branch(goto_), startpc); 1085 code.resolve(loopDone); 1086 } else { 1087 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); 1088 code.resolve(loopEnv.info.cont); 1089 genStats(step, loopEnv); 1090 if (code.isAlive()) { 1091 CondItem c; 1092 if (cond != null) { 1093 code.statBegin(cond.pos); 1094 Assert.check(code.state.stacksize == 0); 1095 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); 1096 } else { 1097 c = items.makeCondItem(goto_); 1098 } 1099 code.resolve(c.jumpTrue(), startpc); 1100 Assert.check(code.state.stacksize == 0); 1101 code.resolve(c.falseJumps); 1102 } 1103 } 1104 Chain exit = loopEnv.info.exit; 1105 if (exit != null) { 1106 code.resolve(exit); 1107 exit.state.defined.excludeFrom(code.nextreg); 1108 } 1109 } 1110 1111 public void visitForeachLoop(JCEnhancedForLoop tree) { 1112 throw new AssertionError(); // should have been removed by Lower. 1113 } 1114 1115 public void visitLabelled(JCLabeledStatement tree) { 1116 Env<GenContext> localEnv = env.dup(tree, new GenContext()); 1117 genStat(tree.body, localEnv, CRT_STATEMENT); 1118 Chain exit = localEnv.info.exit; 1119 if (exit != null) { 1120 code.resolve(exit); 1121 exit.state.defined.excludeFrom(code.nextreg); 1122 } 1123 } 1124 1125 public void visitSwitch(JCSwitch tree) { 1126 int limit = code.nextreg; 1127 Assert.check(!tree.selector.type.hasTag(CLASS)); 1128 int startpcCrt = genCrt ? code.curCP() : 0; 1129 Assert.check(code.state.stacksize == 0); 1130 Item sel = genExpr(tree.selector, syms.intType); 1131 List<JCCase> cases = tree.cases; 1132 if (cases.isEmpty()) { 1133 // We are seeing: switch <sel> {} 1134 sel.load().drop(); 1135 if (genCrt) 1136 code.crt.put(TreeInfo.skipParens(tree.selector), 1137 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP()); 1138 } else { 1139 // We are seeing a nonempty switch. 1140 sel.load(); 1141 if (genCrt) 1142 code.crt.put(TreeInfo.skipParens(tree.selector), 1143 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP()); 1144 Env<GenContext> switchEnv = env.dup(tree, new GenContext()); 1145 switchEnv.info.isSwitch = true; 1146 1147 // Compute number of labels and minimum and maximum label values. 1148 // For each case, store its label in an array. 1149 int lo = Integer.MAX_VALUE; // minimum label. 1150 int hi = Integer.MIN_VALUE; // maximum label. 1151 int nlabels = 0; // number of labels. 1152 1153 int[] labels = new int[cases.length()]; // the label array. 1154 int defaultIndex = -1; // the index of the default clause. 1155 1156 List<JCCase> l = cases; 1157 for (int i = 0; i < labels.length; i++) { 1158 if (l.head.pat != null) { 1159 int val = ((Number)l.head.pat.type.constValue()).intValue(); 1160 labels[i] = val; 1161 if (val < lo) lo = val; 1162 if (hi < val) hi = val; 1163 nlabels++; 1164 } else { 1165 Assert.check(defaultIndex == -1); 1166 defaultIndex = i; 1167 } 1168 l = l.tail; 1169 } 1170 1171 // Determine whether to issue a tableswitch or a lookupswitch 1172 // instruction. 1173 long table_space_cost = 4 + ((long) hi - lo + 1); // words 1174 long table_time_cost = 3; // comparisons 1175 long lookup_space_cost = 3 + 2 * (long) nlabels; 1176 long lookup_time_cost = nlabels; 1177 int opcode = 1178 nlabels > 0 && 1179 table_space_cost + 3 * table_time_cost <= 1180 lookup_space_cost + 3 * lookup_time_cost 1181 ? 1182 tableswitch : lookupswitch; 1183 1184 int startpc = code.curCP(); // the position of the selector operation 1185 code.emitop0(opcode); 1186 code.align(4); 1187 int tableBase = code.curCP(); // the start of the jump table 1188 int[] offsets = null; // a table of offsets for a lookupswitch 1189 code.emit4(-1); // leave space for default offset 1190 if (opcode == tableswitch) { 1191 code.emit4(lo); // minimum label 1192 code.emit4(hi); // maximum label 1193 for (long i = lo; i <= hi; i++) { // leave space for jump table 1194 code.emit4(-1); 1195 } 1196 } else { 1197 code.emit4(nlabels); // number of labels 1198 for (int i = 0; i < nlabels; i++) { 1199 code.emit4(-1); code.emit4(-1); // leave space for lookup table 1200 } 1201 offsets = new int[labels.length]; 1202 } 1203 Code.State stateSwitch = code.state.dup(); 1204 code.markDead(); 1205 1206 // For each case do: 1207 l = cases; 1208 for (int i = 0; i < labels.length; i++) { 1209 JCCase c = l.head; 1210 l = l.tail; 1211 1212 int pc = code.entryPoint(stateSwitch); 1213 // Insert offset directly into code or else into the 1214 // offsets table. 1215 if (i != defaultIndex) { 1216 if (opcode == tableswitch) { 1217 code.put4( 1218 tableBase + 4 * (labels[i] - lo + 3), 1219 pc - startpc); 1220 } else { 1221 offsets[i] = pc - startpc; 1222 } 1223 } else { 1224 code.put4(tableBase, pc - startpc); 1225 } 1226 1227 // Generate code for the statements in this case. 1228 genStats(c.stats, switchEnv, CRT_FLOW_TARGET); 1229 } 1230 1231 // Resolve all breaks. 1232 Chain exit = switchEnv.info.exit; 1233 if (exit != null) { 1234 code.resolve(exit); 1235 exit.state.defined.excludeFrom(code.nextreg); 1236 } 1237 1238 // If we have not set the default offset, we do so now. 1239 if (code.get4(tableBase) == -1) { 1240 code.put4(tableBase, code.entryPoint(stateSwitch) - startpc); 1241 } 1242 1243 if (opcode == tableswitch) { 1244 // Let any unfilled slots point to the default case. 1245 int defaultOffset = code.get4(tableBase); 1246 for (long i = lo; i <= hi; i++) { 1247 int t = (int)(tableBase + 4 * (i - lo + 3)); 1248 if (code.get4(t) == -1) 1249 code.put4(t, defaultOffset); 1250 } 1251 } else { 1252 // Sort non-default offsets and copy into lookup table. 1253 if (defaultIndex >= 0) 1254 for (int i = defaultIndex; i < labels.length - 1; i++) { 1255 labels[i] = labels[i+1]; 1256 offsets[i] = offsets[i+1]; 1257 } 1258 if (nlabels > 0) 1259 qsort2(labels, offsets, 0, nlabels - 1); 1260 for (int i = 0; i < nlabels; i++) { 1261 int caseidx = tableBase + 8 * (i + 1); 1262 code.put4(caseidx, labels[i]); 1263 code.put4(caseidx + 4, offsets[i]); 1264 } 1265 } 1266 } 1267 code.endScopes(limit); 1268 } 1269//where 1270 /** Sort (int) arrays of keys and values 1271 */ 1272 static void qsort2(int[] keys, int[] values, int lo, int hi) { 1273 int i = lo; 1274 int j = hi; 1275 int pivot = keys[(i+j)/2]; 1276 do { 1277 while (keys[i] < pivot) i++; 1278 while (pivot < keys[j]) j--; 1279 if (i <= j) { 1280 int temp1 = keys[i]; 1281 keys[i] = keys[j]; 1282 keys[j] = temp1; 1283 int temp2 = values[i]; 1284 values[i] = values[j]; 1285 values[j] = temp2; 1286 i++; 1287 j--; 1288 } 1289 } while (i <= j); 1290 if (lo < j) qsort2(keys, values, lo, j); 1291 if (i < hi) qsort2(keys, values, i, hi); 1292 } 1293 1294 public void visitSynchronized(JCSynchronized tree) { 1295 int limit = code.nextreg; 1296 // Generate code to evaluate lock and save in temporary variable. 1297 final LocalItem lockVar = makeTemp(syms.objectType); 1298 Assert.check(code.state.stacksize == 0); 1299 genExpr(tree.lock, tree.lock.type).load().duplicate(); 1300 lockVar.store(); 1301 1302 // Generate code to enter monitor. 1303 code.emitop0(monitorenter); 1304 code.state.lock(lockVar.reg); 1305 1306 // Generate code for a try statement with given body, no catch clauses 1307 // in a new environment with the "exit-monitor" operation as finalizer. 1308 final Env<GenContext> syncEnv = env.dup(tree, new GenContext()); 1309 syncEnv.info.finalize = new GenFinalizer() { 1310 void gen() { 1311 genLast(); 1312 Assert.check(syncEnv.info.gaps.length() % 2 == 0); 1313 syncEnv.info.gaps.append(code.curCP()); 1314 } 1315 void genLast() { 1316 if (code.isAlive()) { 1317 lockVar.load(); 1318 code.emitop0(monitorexit); 1319 code.state.unlock(lockVar.reg); 1320 } 1321 } 1322 }; 1323 syncEnv.info.gaps = new ListBuffer<>(); 1324 genTry(tree.body, List.<JCCatch>nil(), syncEnv); 1325 code.endScopes(limit); 1326 } 1327 1328 public void visitTry(final JCTry tree) { 1329 // Generate code for a try statement with given body and catch clauses, 1330 // in a new environment which calls the finally block if there is one. 1331 final Env<GenContext> tryEnv = env.dup(tree, new GenContext()); 1332 final Env<GenContext> oldEnv = env; 1333 tryEnv.info.finalize = new GenFinalizer() { 1334 void gen() { 1335 Assert.check(tryEnv.info.gaps.length() % 2 == 0); 1336 tryEnv.info.gaps.append(code.curCP()); 1337 genLast(); 1338 } 1339 void genLast() { 1340 if (tree.finalizer != null) 1341 genStat(tree.finalizer, oldEnv, CRT_BLOCK); 1342 } 1343 boolean hasFinalizer() { 1344 return tree.finalizer != null; 1345 } 1346 }; 1347 tryEnv.info.gaps = new ListBuffer<>(); 1348 genTry(tree.body, tree.catchers, tryEnv); 1349 } 1350 //where 1351 /** Generate code for a try or synchronized statement 1352 * @param body The body of the try or synchronized statement. 1353 * @param catchers The lis of catch clauses. 1354 * @param env the environment current for the body. 1355 */ 1356 void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) { 1357 int limit = code.nextreg; 1358 int startpc = code.curCP(); 1359 Code.State stateTry = code.state.dup(); 1360 genStat(body, env, CRT_BLOCK); 1361 int endpc = code.curCP(); 1362 boolean hasFinalizer = 1363 env.info.finalize != null && 1364 env.info.finalize.hasFinalizer(); 1365 List<Integer> gaps = env.info.gaps.toList(); 1366 code.statBegin(TreeInfo.endPos(body)); 1367 genFinalizer(env); 1368 code.statBegin(TreeInfo.endPos(env.tree)); 1369 Chain exitChain = code.branch(goto_); 1370 endFinalizerGap(env); 1371 if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) { 1372 // start off with exception on stack 1373 code.entryPoint(stateTry, l.head.param.sym.type); 1374 genCatch(l.head, env, startpc, endpc, gaps); 1375 genFinalizer(env); 1376 if (hasFinalizer || l.tail.nonEmpty()) { 1377 code.statBegin(TreeInfo.endPos(env.tree)); 1378 exitChain = Code.mergeChains(exitChain, 1379 code.branch(goto_)); 1380 } 1381 endFinalizerGap(env); 1382 } 1383 if (hasFinalizer) { 1384 // Create a new register segement to avoid allocating 1385 // the same variables in finalizers and other statements. 1386 code.newRegSegment(); 1387 1388 // Add a catch-all clause. 1389 1390 // start off with exception on stack 1391 int catchallpc = code.entryPoint(stateTry, syms.throwableType); 1392 1393 // Register all exception ranges for catch all clause. 1394 // The range of the catch all clause is from the beginning 1395 // of the try or synchronized block until the present 1396 // code pointer excluding all gaps in the current 1397 // environment's GenContext. 1398 int startseg = startpc; 1399 while (env.info.gaps.nonEmpty()) { 1400 int endseg = env.info.gaps.next().intValue(); 1401 registerCatch(body.pos(), startseg, endseg, 1402 catchallpc, 0); 1403 startseg = env.info.gaps.next().intValue(); 1404 } 1405 code.statBegin(TreeInfo.finalizerPos(env.tree)); 1406 code.markStatBegin(); 1407 1408 Item excVar = makeTemp(syms.throwableType); 1409 excVar.store(); 1410 genFinalizer(env); 1411 excVar.load(); 1412 registerCatch(body.pos(), startseg, 1413 env.info.gaps.next().intValue(), 1414 catchallpc, 0); 1415 code.emitop0(athrow); 1416 code.markDead(); 1417 1418 // If there are jsr's to this finalizer, ... 1419 if (env.info.cont != null) { 1420 // Resolve all jsr's. 1421 code.resolve(env.info.cont); 1422 1423 // Mark statement line number 1424 code.statBegin(TreeInfo.finalizerPos(env.tree)); 1425 code.markStatBegin(); 1426 1427 // Save return address. 1428 LocalItem retVar = makeTemp(syms.throwableType); 1429 retVar.store(); 1430 1431 // Generate finalizer code. 1432 env.info.finalize.genLast(); 1433 1434 // Return. 1435 code.emitop1w(ret, retVar.reg); 1436 code.markDead(); 1437 } 1438 } 1439 // Resolve all breaks. 1440 code.resolve(exitChain); 1441 1442 code.endScopes(limit); 1443 } 1444 1445 /** Generate code for a catch clause. 1446 * @param tree The catch clause. 1447 * @param env The environment current in the enclosing try. 1448 * @param startpc Start pc of try-block. 1449 * @param endpc End pc of try-block. 1450 */ 1451 void genCatch(JCCatch tree, 1452 Env<GenContext> env, 1453 int startpc, int endpc, 1454 List<Integer> gaps) { 1455 if (startpc != endpc) { 1456 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypeExprs 1457 = catchTypesWithAnnotations(tree); 1458 while (gaps.nonEmpty()) { 1459 for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) { 1460 JCExpression subCatch = subCatch1.snd; 1461 int catchType = makeRef(tree.pos(), subCatch.type); 1462 int end = gaps.head.intValue(); 1463 registerCatch(tree.pos(), 1464 startpc, end, code.curCP(), 1465 catchType); 1466 for (Attribute.TypeCompound tc : subCatch1.fst) { 1467 tc.position.setCatchInfo(catchType, startpc); 1468 } 1469 } 1470 gaps = gaps.tail; 1471 startpc = gaps.head.intValue(); 1472 gaps = gaps.tail; 1473 } 1474 if (startpc < endpc) { 1475 for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) { 1476 JCExpression subCatch = subCatch1.snd; 1477 int catchType = makeRef(tree.pos(), subCatch.type); 1478 registerCatch(tree.pos(), 1479 startpc, endpc, code.curCP(), 1480 catchType); 1481 for (Attribute.TypeCompound tc : subCatch1.fst) { 1482 tc.position.setCatchInfo(catchType, startpc); 1483 } 1484 } 1485 } 1486 VarSymbol exparam = tree.param.sym; 1487 code.statBegin(tree.pos); 1488 code.markStatBegin(); 1489 int limit = code.nextreg; 1490 code.newLocal(exparam); 1491 items.makeLocalItem(exparam).store(); 1492 code.statBegin(TreeInfo.firstStatPos(tree.body)); 1493 genStat(tree.body, env, CRT_BLOCK); 1494 code.endScopes(limit); 1495 code.statBegin(TreeInfo.endPos(tree.body)); 1496 } 1497 } 1498 // where 1499 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotations(JCCatch tree) { 1500 return TreeInfo.isMultiCatch(tree) ? 1501 catchTypesWithAnnotationsFromMulticatch((JCTypeUnion)tree.param.vartype, tree.param.sym.getRawTypeAttributes()) : 1502 List.of(new Pair<>(tree.param.sym.getRawTypeAttributes(), tree.param.vartype)); 1503 } 1504 // where 1505 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotationsFromMulticatch(JCTypeUnion tree, List<TypeCompound> first) { 1506 List<JCExpression> alts = tree.alternatives; 1507 List<Pair<List<TypeCompound>, JCExpression>> res = List.of(new Pair<>(first, alts.head)); 1508 alts = alts.tail; 1509 1510 while(alts != null && alts.head != null) { 1511 JCExpression alt = alts.head; 1512 if (alt instanceof JCAnnotatedType) { 1513 JCAnnotatedType a = (JCAnnotatedType)alt; 1514 res = res.prepend(new Pair<>(annotate.fromAnnotations(a.annotations), alt)); 1515 } else { 1516 res = res.prepend(new Pair<>(List.nil(), alt)); 1517 } 1518 alts = alts.tail; 1519 } 1520 return res.reverse(); 1521 } 1522 1523 /** Register a catch clause in the "Exceptions" code-attribute. 1524 */ 1525 void registerCatch(DiagnosticPosition pos, 1526 int startpc, int endpc, 1527 int handler_pc, int catch_type) { 1528 char startpc1 = (char)startpc; 1529 char endpc1 = (char)endpc; 1530 char handler_pc1 = (char)handler_pc; 1531 if (startpc1 == startpc && 1532 endpc1 == endpc && 1533 handler_pc1 == handler_pc) { 1534 code.addCatch(startpc1, endpc1, handler_pc1, 1535 (char)catch_type); 1536 } else { 1537 log.error(pos, "limit.code.too.large.for.try.stmt"); 1538 nerrs++; 1539 } 1540 } 1541 1542 public void visitIf(JCIf tree) { 1543 int limit = code.nextreg; 1544 Chain thenExit = null; 1545 Assert.check(code.state.stacksize == 0); 1546 CondItem c = genCond(TreeInfo.skipParens(tree.cond), 1547 CRT_FLOW_CONTROLLER); 1548 Chain elseChain = c.jumpFalse(); 1549 Assert.check(code.state.stacksize == 0); 1550 if (!c.isFalse()) { 1551 code.resolve(c.trueJumps); 1552 genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET); 1553 thenExit = code.branch(goto_); 1554 } 1555 if (elseChain != null) { 1556 code.resolve(elseChain); 1557 if (tree.elsepart != null) { 1558 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET); 1559 } 1560 } 1561 code.resolve(thenExit); 1562 code.endScopes(limit); 1563 Assert.check(code.state.stacksize == 0); 1564 } 1565 1566 public void visitExec(JCExpressionStatement tree) { 1567 // Optimize x++ to ++x and x-- to --x. 1568 JCExpression e = tree.expr; 1569 switch (e.getTag()) { 1570 case POSTINC: 1571 ((JCUnary) e).setTag(PREINC); 1572 break; 1573 case POSTDEC: 1574 ((JCUnary) e).setTag(PREDEC); 1575 break; 1576 } 1577 Assert.check(code.state.stacksize == 0); 1578 genExpr(tree.expr, tree.expr.type).drop(); 1579 Assert.check(code.state.stacksize == 0); 1580 } 1581 1582 public void visitBreak(JCBreak tree) { 1583 Env<GenContext> targetEnv = unwind(tree.target, env); 1584 Assert.check(code.state.stacksize == 0); 1585 targetEnv.info.addExit(code.branch(goto_)); 1586 endFinalizerGaps(env, targetEnv); 1587 } 1588 1589 public void visitContinue(JCContinue tree) { 1590 Env<GenContext> targetEnv = unwind(tree.target, env); 1591 Assert.check(code.state.stacksize == 0); 1592 targetEnv.info.addCont(code.branch(goto_)); 1593 endFinalizerGaps(env, targetEnv); 1594 } 1595 1596 public void visitReturn(JCReturn tree) { 1597 int limit = code.nextreg; 1598 final Env<GenContext> targetEnv; 1599 1600 /* Save and then restore the location of the return in case a finally 1601 * is expanded (with unwind()) in the middle of our bytecodes. 1602 */ 1603 int tmpPos = code.pendingStatPos; 1604 if (tree.expr != null) { 1605 Assert.check(code.state.stacksize == 0); 1606 Item r = genExpr(tree.expr, pt).load(); 1607 if (hasFinally(env.enclMethod, env)) { 1608 r = makeTemp(pt); 1609 r.store(); 1610 } 1611 targetEnv = unwind(env.enclMethod, env); 1612 code.pendingStatPos = tmpPos; 1613 r.load(); 1614 code.emitop0(ireturn + Code.truncate(Code.typecode(pt))); 1615 } else { 1616 targetEnv = unwind(env.enclMethod, env); 1617 code.pendingStatPos = tmpPos; 1618 code.emitop0(return_); 1619 } 1620 endFinalizerGaps(env, targetEnv); 1621 code.endScopes(limit); 1622 } 1623 1624 public void visitThrow(JCThrow tree) { 1625 Assert.check(code.state.stacksize == 0); 1626 genExpr(tree.expr, tree.expr.type).load(); 1627 code.emitop0(athrow); 1628 Assert.check(code.state.stacksize == 0); 1629 } 1630 1631/* ************************************************************************ 1632 * Visitor methods for expressions 1633 *************************************************************************/ 1634 1635 public void visitApply(JCMethodInvocation tree) { 1636 setTypeAnnotationPositions(tree.pos); 1637 // Generate code for method. 1638 Item m = genExpr(tree.meth, methodType); 1639 // Generate code for all arguments, where the expected types are 1640 // the parameters of the method's external type (that is, any implicit 1641 // outer instance of a super(...) call appears as first parameter). 1642 MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth); 1643 genArgs(tree.args, 1644 msym.externalType(types).getParameterTypes()); 1645 if (!msym.isDynamic()) { 1646 code.statBegin(tree.pos); 1647 } 1648 result = m.invoke(); 1649 } 1650 1651 public void visitConditional(JCConditional tree) { 1652 Chain thenExit = null; 1653 code.statBegin(tree.cond.pos); 1654 CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER); 1655 Chain elseChain = c.jumpFalse(); 1656 if (!c.isFalse()) { 1657 code.resolve(c.trueJumps); 1658 int startpc = genCrt ? code.curCP() : 0; 1659 code.statBegin(tree.truepart.pos); 1660 genExpr(tree.truepart, pt).load(); 1661 code.state.forceStackTop(tree.type); 1662 if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET, 1663 startpc, code.curCP()); 1664 thenExit = code.branch(goto_); 1665 } 1666 if (elseChain != null) { 1667 code.resolve(elseChain); 1668 int startpc = genCrt ? code.curCP() : 0; 1669 code.statBegin(tree.falsepart.pos); 1670 genExpr(tree.falsepart, pt).load(); 1671 code.state.forceStackTop(tree.type); 1672 if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET, 1673 startpc, code.curCP()); 1674 } 1675 code.resolve(thenExit); 1676 result = items.makeStackItem(pt); 1677 } 1678 1679 private void setTypeAnnotationPositions(int treePos) { 1680 MethodSymbol meth = code.meth; 1681 boolean initOrClinit = code.meth.getKind() == javax.lang.model.element.ElementKind.CONSTRUCTOR 1682 || code.meth.getKind() == javax.lang.model.element.ElementKind.STATIC_INIT; 1683 1684 for (Attribute.TypeCompound ta : meth.getRawTypeAttributes()) { 1685 if (ta.hasUnknownPosition()) 1686 ta.tryFixPosition(); 1687 1688 if (ta.position.matchesPos(treePos)) 1689 ta.position.updatePosOffset(code.cp); 1690 } 1691 1692 if (!initOrClinit) 1693 return; 1694 1695 for (Attribute.TypeCompound ta : meth.owner.getRawTypeAttributes()) { 1696 if (ta.hasUnknownPosition()) 1697 ta.tryFixPosition(); 1698 1699 if (ta.position.matchesPos(treePos)) 1700 ta.position.updatePosOffset(code.cp); 1701 } 1702 1703 ClassSymbol clazz = meth.enclClass(); 1704 for (Symbol s : new com.sun.tools.javac.model.FilteredMemberList(clazz.members())) { 1705 if (!s.getKind().isField()) 1706 continue; 1707 1708 for (Attribute.TypeCompound ta : s.getRawTypeAttributes()) { 1709 if (ta.hasUnknownPosition()) 1710 ta.tryFixPosition(); 1711 1712 if (ta.position.matchesPos(treePos)) 1713 ta.position.updatePosOffset(code.cp); 1714 } 1715 } 1716 } 1717 1718 public void visitNewClass(JCNewClass tree) { 1719 // Enclosing instances or anonymous classes should have been eliminated 1720 // by now. 1721 Assert.check(tree.encl == null && tree.def == null); 1722 setTypeAnnotationPositions(tree.pos); 1723 1724 code.emitop2(new_, makeRef(tree.pos(), tree.type)); 1725 code.emitop0(dup); 1726 1727 // Generate code for all arguments, where the expected types are 1728 // the parameters of the constructor's external type (that is, 1729 // any implicit outer instance appears as first parameter). 1730 genArgs(tree.args, tree.constructor.externalType(types).getParameterTypes()); 1731 1732 items.makeMemberItem(tree.constructor, true).invoke(); 1733 result = items.makeStackItem(tree.type); 1734 } 1735 1736 public void visitNewArray(JCNewArray tree) { 1737 setTypeAnnotationPositions(tree.pos); 1738 1739 if (tree.elems != null) { 1740 Type elemtype = types.elemtype(tree.type); 1741 loadIntConst(tree.elems.length()); 1742 Item arr = makeNewArray(tree.pos(), tree.type, 1); 1743 int i = 0; 1744 for (List<JCExpression> l = tree.elems; l.nonEmpty(); l = l.tail) { 1745 arr.duplicate(); 1746 loadIntConst(i); 1747 i++; 1748 genExpr(l.head, elemtype).load(); 1749 items.makeIndexedItem(elemtype).store(); 1750 } 1751 result = arr; 1752 } else { 1753 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { 1754 genExpr(l.head, syms.intType).load(); 1755 } 1756 result = makeNewArray(tree.pos(), tree.type, tree.dims.length()); 1757 } 1758 } 1759//where 1760 /** Generate code to create an array with given element type and number 1761 * of dimensions. 1762 */ 1763 Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) { 1764 Type elemtype = types.elemtype(type); 1765 if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) { 1766 log.error(pos, "limit.dimensions"); 1767 nerrs++; 1768 } 1769 int elemcode = Code.arraycode(elemtype); 1770 if (elemcode == 0 || (elemcode == 1 && ndims == 1)) { 1771 code.emitAnewarray(makeRef(pos, elemtype), type); 1772 } else if (elemcode == 1) { 1773 code.emitMultianewarray(ndims, makeRef(pos, type), type); 1774 } else { 1775 code.emitNewarray(elemcode, type); 1776 } 1777 return items.makeStackItem(type); 1778 } 1779 1780 public void visitParens(JCParens tree) { 1781 result = genExpr(tree.expr, tree.expr.type); 1782 } 1783 1784 public void visitAssign(JCAssign tree) { 1785 Item l = genExpr(tree.lhs, tree.lhs.type); 1786 genExpr(tree.rhs, tree.lhs.type).load(); 1787 if (tree.rhs.type.hasTag(BOT)) { 1788 /* This is just a case of widening reference conversion that per 5.1.5 simply calls 1789 for "regarding a reference as having some other type in a manner that can be proved 1790 correct at compile time." 1791 */ 1792 code.state.forceStackTop(tree.lhs.type); 1793 } 1794 result = items.makeAssignItem(l); 1795 } 1796 1797 public void visitAssignop(JCAssignOp tree) { 1798 OperatorSymbol operator = (OperatorSymbol) tree.operator; 1799 Item l; 1800 if (operator.opcode == string_add) { 1801 l = concat.makeConcat(tree); 1802 } else { 1803 // Generate code for first expression 1804 l = genExpr(tree.lhs, tree.lhs.type); 1805 1806 // If we have an increment of -32768 to +32767 of a local 1807 // int variable we can use an incr instruction instead of 1808 // proceeding further. 1809 if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) && 1810 l instanceof LocalItem && 1811 tree.lhs.type.getTag().isSubRangeOf(INT) && 1812 tree.rhs.type.getTag().isSubRangeOf(INT) && 1813 tree.rhs.type.constValue() != null) { 1814 int ival = ((Number) tree.rhs.type.constValue()).intValue(); 1815 if (tree.hasTag(MINUS_ASG)) ival = -ival; 1816 ((LocalItem)l).incr(ival); 1817 result = l; 1818 return; 1819 } 1820 // Otherwise, duplicate expression, load one copy 1821 // and complete binary operation. 1822 l.duplicate(); 1823 l.coerce(operator.type.getParameterTypes().head).load(); 1824 completeBinop(tree.lhs, tree.rhs, operator).coerce(tree.lhs.type); 1825 } 1826 result = items.makeAssignItem(l); 1827 } 1828 1829 public void visitUnary(JCUnary tree) { 1830 OperatorSymbol operator = (OperatorSymbol)tree.operator; 1831 if (tree.hasTag(NOT)) { 1832 CondItem od = genCond(tree.arg, false); 1833 result = od.negate(); 1834 } else { 1835 Item od = genExpr(tree.arg, operator.type.getParameterTypes().head); 1836 switch (tree.getTag()) { 1837 case POS: 1838 result = od.load(); 1839 break; 1840 case NEG: 1841 result = od.load(); 1842 code.emitop0(operator.opcode); 1843 break; 1844 case COMPL: 1845 result = od.load(); 1846 emitMinusOne(od.typecode); 1847 code.emitop0(operator.opcode); 1848 break; 1849 case PREINC: case PREDEC: 1850 od.duplicate(); 1851 if (od instanceof LocalItem && 1852 (operator.opcode == iadd || operator.opcode == isub)) { 1853 ((LocalItem)od).incr(tree.hasTag(PREINC) ? 1 : -1); 1854 result = od; 1855 } else { 1856 od.load(); 1857 code.emitop0(one(od.typecode)); 1858 code.emitop0(operator.opcode); 1859 // Perform narrowing primitive conversion if byte, 1860 // char, or short. Fix for 4304655. 1861 if (od.typecode != INTcode && 1862 Code.truncate(od.typecode) == INTcode) 1863 code.emitop0(int2byte + od.typecode - BYTEcode); 1864 result = items.makeAssignItem(od); 1865 } 1866 break; 1867 case POSTINC: case POSTDEC: 1868 od.duplicate(); 1869 if (od instanceof LocalItem && 1870 (operator.opcode == iadd || operator.opcode == isub)) { 1871 Item res = od.load(); 1872 ((LocalItem)od).incr(tree.hasTag(POSTINC) ? 1 : -1); 1873 result = res; 1874 } else { 1875 Item res = od.load(); 1876 od.stash(od.typecode); 1877 code.emitop0(one(od.typecode)); 1878 code.emitop0(operator.opcode); 1879 // Perform narrowing primitive conversion if byte, 1880 // char, or short. Fix for 4304655. 1881 if (od.typecode != INTcode && 1882 Code.truncate(od.typecode) == INTcode) 1883 code.emitop0(int2byte + od.typecode - BYTEcode); 1884 od.store(); 1885 result = res; 1886 } 1887 break; 1888 case NULLCHK: 1889 result = od.load(); 1890 code.emitop0(dup); 1891 genNullCheck(tree.pos()); 1892 break; 1893 default: 1894 Assert.error(); 1895 } 1896 } 1897 } 1898 1899 /** Generate a null check from the object value at stack top. */ 1900 private void genNullCheck(DiagnosticPosition pos) { 1901 if (allowBetterNullChecks) { 1902 callMethod(pos, syms.objectsType, names.requireNonNull, 1903 List.of(syms.objectType), true); 1904 } else { 1905 callMethod(pos, syms.objectType, names.getClass, 1906 List.<Type>nil(), false); 1907 } 1908 code.emitop0(pop); 1909 } 1910 1911 public void visitBinary(JCBinary tree) { 1912 OperatorSymbol operator = (OperatorSymbol)tree.operator; 1913 if (operator.opcode == string_add) { 1914 result = concat.makeConcat(tree); 1915 } else if (tree.hasTag(AND)) { 1916 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); 1917 if (!lcond.isFalse()) { 1918 Chain falseJumps = lcond.jumpFalse(); 1919 code.resolve(lcond.trueJumps); 1920 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET); 1921 result = items. 1922 makeCondItem(rcond.opcode, 1923 rcond.trueJumps, 1924 Code.mergeChains(falseJumps, 1925 rcond.falseJumps)); 1926 } else { 1927 result = lcond; 1928 } 1929 } else if (tree.hasTag(OR)) { 1930 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); 1931 if (!lcond.isTrue()) { 1932 Chain trueJumps = lcond.jumpTrue(); 1933 code.resolve(lcond.falseJumps); 1934 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET); 1935 result = items. 1936 makeCondItem(rcond.opcode, 1937 Code.mergeChains(trueJumps, rcond.trueJumps), 1938 rcond.falseJumps); 1939 } else { 1940 result = lcond; 1941 } 1942 } else { 1943 Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head); 1944 od.load(); 1945 result = completeBinop(tree.lhs, tree.rhs, operator); 1946 } 1947 } 1948 1949 1950 /** Complete generating code for operation, with left operand 1951 * already on stack. 1952 * @param lhs The tree representing the left operand. 1953 * @param rhs The tree representing the right operand. 1954 * @param operator The operator symbol. 1955 */ 1956 Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) { 1957 MethodType optype = (MethodType)operator.type; 1958 int opcode = operator.opcode; 1959 if (opcode >= if_icmpeq && opcode <= if_icmple && 1960 rhs.type.constValue() instanceof Number && 1961 ((Number) rhs.type.constValue()).intValue() == 0) { 1962 opcode = opcode + (ifeq - if_icmpeq); 1963 } else if (opcode >= if_acmpeq && opcode <= if_acmpne && 1964 TreeInfo.isNull(rhs)) { 1965 opcode = opcode + (if_acmp_null - if_acmpeq); 1966 } else { 1967 // The expected type of the right operand is 1968 // the second parameter type of the operator, except for 1969 // shifts with long shiftcount, where we convert the opcode 1970 // to a short shift and the expected type to int. 1971 Type rtype = operator.erasure(types).getParameterTypes().tail.head; 1972 if (opcode >= ishll && opcode <= lushrl) { 1973 opcode = opcode + (ishl - ishll); 1974 rtype = syms.intType; 1975 } 1976 // Generate code for right operand and load. 1977 genExpr(rhs, rtype).load(); 1978 // If there are two consecutive opcode instructions, 1979 // emit the first now. 1980 if (opcode >= (1 << preShift)) { 1981 code.emitop0(opcode >> preShift); 1982 opcode = opcode & 0xFF; 1983 } 1984 } 1985 if (opcode >= ifeq && opcode <= if_acmpne || 1986 opcode == if_acmp_null || opcode == if_acmp_nonnull) { 1987 return items.makeCondItem(opcode); 1988 } else { 1989 code.emitop0(opcode); 1990 return items.makeStackItem(optype.restype); 1991 } 1992 } 1993 1994 public void visitTypeCast(JCTypeCast tree) { 1995 result = genExpr(tree.expr, tree.clazz.type).load(); 1996 setTypeAnnotationPositions(tree.pos); 1997 // Additional code is only needed if we cast to a reference type 1998 // which is not statically a supertype of the expression's type. 1999 // For basic types, the coerce(...) in genExpr(...) will do 2000 // the conversion. 2001 if (!tree.clazz.type.isPrimitive() && 2002 !types.isSameType(tree.expr.type, tree.clazz.type) && 2003 types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) { 2004 code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type)); 2005 } 2006 } 2007 2008 public void visitWildcard(JCWildcard tree) { 2009 throw new AssertionError(this.getClass().getName()); 2010 } 2011 2012 public void visitTypeTest(JCInstanceOf tree) { 2013 genExpr(tree.expr, tree.expr.type).load(); 2014 setTypeAnnotationPositions(tree.pos); 2015 code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type)); 2016 result = items.makeStackItem(syms.booleanType); 2017 } 2018 2019 public void visitIndexed(JCArrayAccess tree) { 2020 genExpr(tree.indexed, tree.indexed.type).load(); 2021 genExpr(tree.index, syms.intType).load(); 2022 result = items.makeIndexedItem(tree.type); 2023 } 2024 2025 public void visitIdent(JCIdent tree) { 2026 Symbol sym = tree.sym; 2027 if (tree.name == names._this || tree.name == names._super) { 2028 Item res = tree.name == names._this 2029 ? items.makeThisItem() 2030 : items.makeSuperItem(); 2031 if (sym.kind == MTH) { 2032 // Generate code to address the constructor. 2033 res.load(); 2034 res = items.makeMemberItem(sym, true); 2035 } 2036 result = res; 2037 } else if (sym.kind == VAR && sym.owner.kind == MTH) { 2038 result = items.makeLocalItem((VarSymbol)sym); 2039 } else if (isInvokeDynamic(sym)) { 2040 result = items.makeDynamicItem(sym); 2041 } else if ((sym.flags() & STATIC) != 0) { 2042 if (!isAccessSuper(env.enclMethod)) 2043 sym = binaryQualifier(sym, env.enclClass.type); 2044 result = items.makeStaticItem(sym); 2045 } else { 2046 items.makeThisItem().load(); 2047 sym = binaryQualifier(sym, env.enclClass.type); 2048 result = items.makeMemberItem(sym, (sym.flags() & PRIVATE) != 0); 2049 } 2050 } 2051 2052 public void visitSelect(JCFieldAccess tree) { 2053 Symbol sym = tree.sym; 2054 2055 if (tree.name == names._class) { 2056 code.emitLdc(makeRef(tree.pos(), tree.selected.type)); 2057 result = items.makeStackItem(pt); 2058 return; 2059 } 2060 2061 Symbol ssym = TreeInfo.symbol(tree.selected); 2062 2063 // Are we selecting via super? 2064 boolean selectSuper = 2065 ssym != null && (ssym.kind == TYP || ssym.name == names._super); 2066 2067 // Are we accessing a member of the superclass in an access method 2068 // resulting from a qualified super? 2069 boolean accessSuper = isAccessSuper(env.enclMethod); 2070 2071 Item base = (selectSuper) 2072 ? items.makeSuperItem() 2073 : genExpr(tree.selected, tree.selected.type); 2074 2075 if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) { 2076 // We are seeing a variable that is constant but its selecting 2077 // expression is not. 2078 if ((sym.flags() & STATIC) != 0) { 2079 if (!selectSuper && (ssym == null || ssym.kind != TYP)) 2080 base = base.load(); 2081 base.drop(); 2082 } else { 2083 base.load(); 2084 genNullCheck(tree.selected.pos()); 2085 } 2086 result = items. 2087 makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue()); 2088 } else { 2089 if (isInvokeDynamic(sym)) { 2090 result = items.makeDynamicItem(sym); 2091 return; 2092 } else { 2093 sym = binaryQualifier(sym, tree.selected.type); 2094 } 2095 if ((sym.flags() & STATIC) != 0) { 2096 if (!selectSuper && (ssym == null || ssym.kind != TYP)) 2097 base = base.load(); 2098 base.drop(); 2099 result = items.makeStaticItem(sym); 2100 } else { 2101 base.load(); 2102 if (sym == syms.lengthVar) { 2103 code.emitop0(arraylength); 2104 result = items.makeStackItem(syms.intType); 2105 } else { 2106 result = items. 2107 makeMemberItem(sym, 2108 (sym.flags() & PRIVATE) != 0 || 2109 selectSuper || accessSuper); 2110 } 2111 } 2112 } 2113 } 2114 2115 public boolean isInvokeDynamic(Symbol sym) { 2116 return sym.kind == MTH && ((MethodSymbol)sym).isDynamic(); 2117 } 2118 2119 public void visitLiteral(JCLiteral tree) { 2120 if (tree.type.hasTag(BOT)) { 2121 code.emitop0(aconst_null); 2122 result = items.makeStackItem(tree.type); 2123 } 2124 else 2125 result = items.makeImmediateItem(tree.type, tree.value); 2126 } 2127 2128 public void visitLetExpr(LetExpr tree) { 2129 letExprDepth++; 2130 int limit = code.nextreg; 2131 genStats(tree.defs, env); 2132 result = genExpr(tree.expr, tree.expr.type).load(); 2133 code.endScopes(limit); 2134 letExprDepth--; 2135 } 2136 2137 private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) { 2138 List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol); 2139 if (prunedInfo != null) { 2140 for (JCTree prunedTree: prunedInfo) { 2141 prunedTree.accept(classReferenceVisitor); 2142 } 2143 } 2144 } 2145 2146/* ************************************************************************ 2147 * main method 2148 *************************************************************************/ 2149 2150 /** Generate code for a class definition. 2151 * @param env The attribution environment that belongs to the 2152 * outermost class containing this class definition. 2153 * We need this for resolving some additional symbols. 2154 * @param cdef The tree representing the class definition. 2155 * @return True if code is generated with no errors. 2156 */ 2157 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) { 2158 try { 2159 attrEnv = env; 2160 ClassSymbol c = cdef.sym; 2161 this.toplevel = env.toplevel; 2162 this.endPosTable = toplevel.endPositions; 2163 c.pool = pool; 2164 pool.reset(); 2165 /* method normalizeDefs() can add references to external classes into the constant pool 2166 */ 2167 cdef.defs = normalizeDefs(cdef.defs, c); 2168 generateReferencesToPrunedTree(c, pool); 2169 Env<GenContext> localEnv = new Env<>(cdef, new GenContext()); 2170 localEnv.toplevel = env.toplevel; 2171 localEnv.enclClass = cdef; 2172 2173 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) { 2174 genDef(l.head, localEnv); 2175 } 2176 if (pool.numEntries() > Pool.MAX_ENTRIES) { 2177 log.error(cdef.pos(), "limit.pool"); 2178 nerrs++; 2179 } 2180 if (nerrs != 0) { 2181 // if errors, discard code 2182 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) { 2183 if (l.head.hasTag(METHODDEF)) 2184 ((JCMethodDecl) l.head).sym.code = null; 2185 } 2186 } 2187 cdef.defs = List.nil(); // discard trees 2188 return nerrs == 0; 2189 } finally { 2190 // note: this method does NOT support recursion. 2191 attrEnv = null; 2192 this.env = null; 2193 toplevel = null; 2194 endPosTable = null; 2195 nerrs = 0; 2196 } 2197 } 2198 2199/* ************************************************************************ 2200 * Auxiliary classes 2201 *************************************************************************/ 2202 2203 /** An abstract class for finalizer generation. 2204 */ 2205 abstract class GenFinalizer { 2206 /** Generate code to clean up when unwinding. */ 2207 abstract void gen(); 2208 2209 /** Generate code to clean up at last. */ 2210 abstract void genLast(); 2211 2212 /** Does this finalizer have some nontrivial cleanup to perform? */ 2213 boolean hasFinalizer() { return true; } 2214 } 2215 2216 /** code generation contexts, 2217 * to be used as type parameter for environments. 2218 */ 2219 static class GenContext { 2220 2221 /** A chain for all unresolved jumps that exit the current environment. 2222 */ 2223 Chain exit = null; 2224 2225 /** A chain for all unresolved jumps that continue in the 2226 * current environment. 2227 */ 2228 Chain cont = null; 2229 2230 /** A closure that generates the finalizer of the current environment. 2231 * Only set for Synchronized and Try contexts. 2232 */ 2233 GenFinalizer finalize = null; 2234 2235 /** Is this a switch statement? If so, allocate registers 2236 * even when the variable declaration is unreachable. 2237 */ 2238 boolean isSwitch = false; 2239 2240 /** A list buffer containing all gaps in the finalizer range, 2241 * where a catch all exception should not apply. 2242 */ 2243 ListBuffer<Integer> gaps = null; 2244 2245 /** Add given chain to exit chain. 2246 */ 2247 void addExit(Chain c) { 2248 exit = Code.mergeChains(c, exit); 2249 } 2250 2251 /** Add given chain to cont chain. 2252 */ 2253 void addCont(Chain c) { 2254 cont = Code.mergeChains(c, cont); 2255 } 2256 } 2257 2258} 2259