1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,2917 @@ 1.4 +/* 1.5 + * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.javac.jvm; 1.30 + 1.31 +import java.util.*; 1.32 + 1.33 +import com.sun.tools.javac.util.*; 1.34 +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 1.35 +import com.sun.tools.javac.util.List; 1.36 +import com.sun.tools.javac.code.*; 1.37 +import com.sun.tools.javac.code.Attribute.TypeCompound; 1.38 +import com.sun.tools.javac.code.Symbol.VarSymbol; 1.39 +import com.sun.tools.javac.comp.*; 1.40 +import com.sun.tools.javac.tree.*; 1.41 + 1.42 +import com.sun.tools.javac.code.Symbol.*; 1.43 +import com.sun.tools.javac.code.Type.*; 1.44 +import com.sun.tools.javac.jvm.Code.*; 1.45 +import com.sun.tools.javac.jvm.Items.*; 1.46 +import com.sun.tools.javac.tree.EndPosTable; 1.47 +import com.sun.tools.javac.tree.JCTree.*; 1.48 + 1.49 +import static com.sun.tools.javac.code.Flags.*; 1.50 +import static com.sun.tools.javac.code.Kinds.*; 1.51 +import static com.sun.tools.javac.code.TypeTag.*; 1.52 +import static com.sun.tools.javac.jvm.ByteCodes.*; 1.53 +import static com.sun.tools.javac.jvm.CRTFlags.*; 1.54 +import static com.sun.tools.javac.main.Option.*; 1.55 +import static com.sun.tools.javac.tree.JCTree.Tag.*; 1.56 + 1.57 +/** This pass maps flat Java (i.e. without inner classes) to bytecodes. 1.58 + * 1.59 + * <p><b>This is NOT part of any supported API. 1.60 + * If you write code that depends on this, you do so at your own risk. 1.61 + * This code and its internal interfaces are subject to change or 1.62 + * deletion without notice.</b> 1.63 + */ 1.64 +public class Gen extends JCTree.Visitor { 1.65 + protected static final Context.Key<Gen> genKey = 1.66 + new Context.Key<Gen>(); 1.67 + 1.68 + private final Log log; 1.69 + private final Symtab syms; 1.70 + private final Check chk; 1.71 + private final Resolve rs; 1.72 + private final TreeMaker make; 1.73 + private final Names names; 1.74 + private final Target target; 1.75 + private final Type stringBufferType; 1.76 + private final Map<Type,Symbol> stringBufferAppend; 1.77 + private Name accessDollar; 1.78 + private final Types types; 1.79 + private final Lower lower; 1.80 + 1.81 + /** Switch: GJ mode? 1.82 + */ 1.83 + private final boolean allowGenerics; 1.84 + 1.85 + /** Set when Miranda method stubs are to be generated. */ 1.86 + private final boolean generateIproxies; 1.87 + 1.88 + /** Format of stackmap tables to be generated. */ 1.89 + private final Code.StackMapFormat stackMap; 1.90 + 1.91 + /** A type that serves as the expected type for all method expressions. 1.92 + */ 1.93 + private final Type methodType; 1.94 + 1.95 + public static Gen instance(Context context) { 1.96 + Gen instance = context.get(genKey); 1.97 + if (instance == null) 1.98 + instance = new Gen(context); 1.99 + return instance; 1.100 + } 1.101 + 1.102 + /** Constant pool, reset by genClass. 1.103 + */ 1.104 + private Pool pool; 1.105 + 1.106 + /** LVTRanges info. 1.107 + */ 1.108 + private LVTRanges lvtRanges; 1.109 + 1.110 + private final boolean typeAnnoAsserts; 1.111 + 1.112 + protected Gen(Context context) { 1.113 + context.put(genKey, this); 1.114 + 1.115 + names = Names.instance(context); 1.116 + log = Log.instance(context); 1.117 + syms = Symtab.instance(context); 1.118 + chk = Check.instance(context); 1.119 + rs = Resolve.instance(context); 1.120 + make = TreeMaker.instance(context); 1.121 + target = Target.instance(context); 1.122 + types = Types.instance(context); 1.123 + methodType = new MethodType(null, null, null, syms.methodClass); 1.124 + allowGenerics = Source.instance(context).allowGenerics(); 1.125 + stringBufferType = target.useStringBuilder() 1.126 + ? syms.stringBuilderType 1.127 + : syms.stringBufferType; 1.128 + stringBufferAppend = new HashMap<Type,Symbol>(); 1.129 + accessDollar = names. 1.130 + fromString("access" + target.syntheticNameChar()); 1.131 + lower = Lower.instance(context); 1.132 + 1.133 + Options options = Options.instance(context); 1.134 + lineDebugInfo = 1.135 + options.isUnset(G_CUSTOM) || 1.136 + options.isSet(G_CUSTOM, "lines"); 1.137 + varDebugInfo = 1.138 + options.isUnset(G_CUSTOM) 1.139 + ? options.isSet(G) 1.140 + : options.isSet(G_CUSTOM, "vars"); 1.141 + if (varDebugInfo) { 1.142 + lvtRanges = LVTRanges.instance(context); 1.143 + } 1.144 + genCrt = options.isSet(XJCOV); 1.145 + debugCode = options.isSet("debugcode"); 1.146 + allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic"); 1.147 + pool = new Pool(types); 1.148 + typeAnnoAsserts = options.isSet("TypeAnnotationAsserts"); 1.149 + 1.150 + generateIproxies = 1.151 + target.requiresIproxy() || 1.152 + options.isSet("miranda"); 1.153 + 1.154 + if (target.generateStackMapTable()) { 1.155 + // ignore cldc because we cannot have both stackmap formats 1.156 + this.stackMap = StackMapFormat.JSR202; 1.157 + } else { 1.158 + if (target.generateCLDCStackmap()) { 1.159 + this.stackMap = StackMapFormat.CLDC; 1.160 + } else { 1.161 + this.stackMap = StackMapFormat.NONE; 1.162 + } 1.163 + } 1.164 + 1.165 + // by default, avoid jsr's for simple finalizers 1.166 + int setjsrlimit = 50; 1.167 + String jsrlimitString = options.get("jsrlimit"); 1.168 + if (jsrlimitString != null) { 1.169 + try { 1.170 + setjsrlimit = Integer.parseInt(jsrlimitString); 1.171 + } catch (NumberFormatException ex) { 1.172 + // ignore ill-formed numbers for jsrlimit 1.173 + } 1.174 + } 1.175 + this.jsrlimit = setjsrlimit; 1.176 + this.useJsrLocally = false; // reset in visitTry 1.177 + } 1.178 + 1.179 + /** Switches 1.180 + */ 1.181 + private final boolean lineDebugInfo; 1.182 + private final boolean varDebugInfo; 1.183 + private final boolean genCrt; 1.184 + private final boolean debugCode; 1.185 + private final boolean allowInvokedynamic; 1.186 + 1.187 + /** Default limit of (approximate) size of finalizer to inline. 1.188 + * Zero means always use jsr. 100 or greater means never use 1.189 + * jsr. 1.190 + */ 1.191 + private final int jsrlimit; 1.192 + 1.193 + /** True if jsr is used. 1.194 + */ 1.195 + private boolean useJsrLocally; 1.196 + 1.197 + /** Code buffer, set by genMethod. 1.198 + */ 1.199 + private Code code; 1.200 + 1.201 + /** Items structure, set by genMethod. 1.202 + */ 1.203 + private Items items; 1.204 + 1.205 + /** Environment for symbol lookup, set by genClass 1.206 + */ 1.207 + private Env<AttrContext> attrEnv; 1.208 + 1.209 + /** The top level tree. 1.210 + */ 1.211 + private JCCompilationUnit toplevel; 1.212 + 1.213 + /** The number of code-gen errors in this class. 1.214 + */ 1.215 + private int nerrs = 0; 1.216 + 1.217 + /** An object containing mappings of syntax trees to their 1.218 + * ending source positions. 1.219 + */ 1.220 + EndPosTable endPosTable; 1.221 + 1.222 + /** Generate code to load an integer constant. 1.223 + * @param n The integer to be loaded. 1.224 + */ 1.225 + void loadIntConst(int n) { 1.226 + items.makeImmediateItem(syms.intType, n).load(); 1.227 + } 1.228 + 1.229 + /** The opcode that loads a zero constant of a given type code. 1.230 + * @param tc The given type code (@see ByteCode). 1.231 + */ 1.232 + public static int zero(int tc) { 1.233 + switch(tc) { 1.234 + case INTcode: case BYTEcode: case SHORTcode: case CHARcode: 1.235 + return iconst_0; 1.236 + case LONGcode: 1.237 + return lconst_0; 1.238 + case FLOATcode: 1.239 + return fconst_0; 1.240 + case DOUBLEcode: 1.241 + return dconst_0; 1.242 + default: 1.243 + throw new AssertionError("zero"); 1.244 + } 1.245 + } 1.246 + 1.247 + /** The opcode that loads a one constant of a given type code. 1.248 + * @param tc The given type code (@see ByteCode). 1.249 + */ 1.250 + public static int one(int tc) { 1.251 + return zero(tc) + 1; 1.252 + } 1.253 + 1.254 + /** Generate code to load -1 of the given type code (either int or long). 1.255 + * @param tc The given type code (@see ByteCode). 1.256 + */ 1.257 + void emitMinusOne(int tc) { 1.258 + if (tc == LONGcode) { 1.259 + items.makeImmediateItem(syms.longType, new Long(-1)).load(); 1.260 + } else { 1.261 + code.emitop0(iconst_m1); 1.262 + } 1.263 + } 1.264 + 1.265 + /** Construct a symbol to reflect the qualifying type that should 1.266 + * appear in the byte code as per JLS 13.1. 1.267 + * 1.268 + * For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except 1.269 + * for those cases where we need to work around VM bugs). 1.270 + * 1.271 + * For {@literal target <= 1.1}: If qualified variable or method is defined in a 1.272 + * non-accessible class, clone it with the qualifier class as owner. 1.273 + * 1.274 + * @param sym The accessed symbol 1.275 + * @param site The qualifier's type. 1.276 + */ 1.277 + Symbol binaryQualifier(Symbol sym, Type site) { 1.278 + 1.279 + if (site.hasTag(ARRAY)) { 1.280 + if (sym == syms.lengthVar || 1.281 + sym.owner != syms.arrayClass) 1.282 + return sym; 1.283 + // array clone can be qualified by the array type in later targets 1.284 + Symbol qualifier = target.arrayBinaryCompatibility() 1.285 + ? new ClassSymbol(Flags.PUBLIC, site.tsym.name, 1.286 + site, syms.noSymbol) 1.287 + : syms.objectType.tsym; 1.288 + return sym.clone(qualifier); 1.289 + } 1.290 + 1.291 + if (sym.owner == site.tsym || 1.292 + (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) { 1.293 + return sym; 1.294 + } 1.295 + if (!target.obeyBinaryCompatibility()) 1.296 + return rs.isAccessible(attrEnv, (TypeSymbol)sym.owner) 1.297 + ? sym 1.298 + : sym.clone(site.tsym); 1.299 + 1.300 + if (!target.interfaceFieldsBinaryCompatibility()) { 1.301 + if ((sym.owner.flags() & INTERFACE) != 0 && sym.kind == VAR) 1.302 + return sym; 1.303 + } 1.304 + 1.305 + // leave alone methods inherited from Object 1.306 + // JLS 13.1. 1.307 + if (sym.owner == syms.objectType.tsym) 1.308 + return sym; 1.309 + 1.310 + if (!target.interfaceObjectOverridesBinaryCompatibility()) { 1.311 + if ((sym.owner.flags() & INTERFACE) != 0 && 1.312 + syms.objectType.tsym.members().lookup(sym.name).scope != null) 1.313 + return sym; 1.314 + } 1.315 + 1.316 + return sym.clone(site.tsym); 1.317 + } 1.318 + 1.319 + /** Insert a reference to given type in the constant pool, 1.320 + * checking for an array with too many dimensions; 1.321 + * return the reference's index. 1.322 + * @param type The type for which a reference is inserted. 1.323 + */ 1.324 + int makeRef(DiagnosticPosition pos, Type type) { 1.325 + checkDimension(pos, type); 1.326 + if (type.isAnnotated()) { 1.327 + // Treat annotated types separately - we don't want 1.328 + // to collapse all of them - at least for annotated 1.329 + // exceptions. 1.330 + // TODO: review this. 1.331 + return pool.put((Object)type); 1.332 + } else { 1.333 + return pool.put(type.hasTag(CLASS) ? (Object)type.tsym : (Object)type); 1.334 + } 1.335 + } 1.336 + 1.337 + /** Check if the given type is an array with too many dimensions. 1.338 + */ 1.339 + private void checkDimension(DiagnosticPosition pos, Type t) { 1.340 + switch (t.getTag()) { 1.341 + case METHOD: 1.342 + checkDimension(pos, t.getReturnType()); 1.343 + for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail) 1.344 + checkDimension(pos, args.head); 1.345 + break; 1.346 + case ARRAY: 1.347 + if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) { 1.348 + log.error(pos, "limit.dimensions"); 1.349 + nerrs++; 1.350 + } 1.351 + break; 1.352 + default: 1.353 + break; 1.354 + } 1.355 + } 1.356 + 1.357 + /** Create a tempory variable. 1.358 + * @param type The variable's type. 1.359 + */ 1.360 + LocalItem makeTemp(Type type) { 1.361 + VarSymbol v = new VarSymbol(Flags.SYNTHETIC, 1.362 + names.empty, 1.363 + type, 1.364 + env.enclMethod.sym); 1.365 + code.newLocal(v); 1.366 + return items.makeLocalItem(v); 1.367 + } 1.368 + 1.369 + /** Generate code to call a non-private method or constructor. 1.370 + * @param pos Position to be used for error reporting. 1.371 + * @param site The type of which the method is a member. 1.372 + * @param name The method's name. 1.373 + * @param argtypes The method's argument types. 1.374 + * @param isStatic A flag that indicates whether we call a 1.375 + * static or instance method. 1.376 + */ 1.377 + void callMethod(DiagnosticPosition pos, 1.378 + Type site, Name name, List<Type> argtypes, 1.379 + boolean isStatic) { 1.380 + Symbol msym = rs. 1.381 + resolveInternalMethod(pos, attrEnv, site, name, argtypes, null); 1.382 + if (isStatic) items.makeStaticItem(msym).invoke(); 1.383 + else items.makeMemberItem(msym, name == names.init).invoke(); 1.384 + } 1.385 + 1.386 + /** Is the given method definition an access method 1.387 + * resulting from a qualified super? This is signified by an odd 1.388 + * access code. 1.389 + */ 1.390 + private boolean isAccessSuper(JCMethodDecl enclMethod) { 1.391 + return 1.392 + (enclMethod.mods.flags & SYNTHETIC) != 0 && 1.393 + isOddAccessName(enclMethod.name); 1.394 + } 1.395 + 1.396 + /** Does given name start with "access$" and end in an odd digit? 1.397 + */ 1.398 + private boolean isOddAccessName(Name name) { 1.399 + return 1.400 + name.startsWith(accessDollar) && 1.401 + (name.getByteAt(name.getByteLength() - 1) & 1) == 1; 1.402 + } 1.403 + 1.404 +/* ************************************************************************ 1.405 + * Non-local exits 1.406 + *************************************************************************/ 1.407 + 1.408 + /** Generate code to invoke the finalizer associated with given 1.409 + * environment. 1.410 + * Any calls to finalizers are appended to the environments `cont' chain. 1.411 + * Mark beginning of gap in catch all range for finalizer. 1.412 + */ 1.413 + void genFinalizer(Env<GenContext> env) { 1.414 + if (code.isAlive() && env.info.finalize != null) 1.415 + env.info.finalize.gen(); 1.416 + } 1.417 + 1.418 + /** Generate code to call all finalizers of structures aborted by 1.419 + * a non-local 1.420 + * exit. Return target environment of the non-local exit. 1.421 + * @param target The tree representing the structure that's aborted 1.422 + * @param env The environment current at the non-local exit. 1.423 + */ 1.424 + Env<GenContext> unwind(JCTree target, Env<GenContext> env) { 1.425 + Env<GenContext> env1 = env; 1.426 + while (true) { 1.427 + genFinalizer(env1); 1.428 + if (env1.tree == target) break; 1.429 + env1 = env1.next; 1.430 + } 1.431 + return env1; 1.432 + } 1.433 + 1.434 + /** Mark end of gap in catch-all range for finalizer. 1.435 + * @param env the environment which might contain the finalizer 1.436 + * (if it does, env.info.gaps != null). 1.437 + */ 1.438 + void endFinalizerGap(Env<GenContext> env) { 1.439 + if (env.info.gaps != null && env.info.gaps.length() % 2 == 1) 1.440 + env.info.gaps.append(code.curCP()); 1.441 + } 1.442 + 1.443 + /** Mark end of all gaps in catch-all ranges for finalizers of environments 1.444 + * lying between, and including to two environments. 1.445 + * @param from the most deeply nested environment to mark 1.446 + * @param to the least deeply nested environment to mark 1.447 + */ 1.448 + void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) { 1.449 + Env<GenContext> last = null; 1.450 + while (last != to) { 1.451 + endFinalizerGap(from); 1.452 + last = from; 1.453 + from = from.next; 1.454 + } 1.455 + } 1.456 + 1.457 + /** Do any of the structures aborted by a non-local exit have 1.458 + * finalizers that require an empty stack? 1.459 + * @param target The tree representing the structure that's aborted 1.460 + * @param env The environment current at the non-local exit. 1.461 + */ 1.462 + boolean hasFinally(JCTree target, Env<GenContext> env) { 1.463 + while (env.tree != target) { 1.464 + if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer()) 1.465 + return true; 1.466 + env = env.next; 1.467 + } 1.468 + return false; 1.469 + } 1.470 + 1.471 +/* ************************************************************************ 1.472 + * Normalizing class-members. 1.473 + *************************************************************************/ 1.474 + 1.475 + /** Distribute member initializer code into constructors and {@code <clinit>} 1.476 + * method. 1.477 + * @param defs The list of class member declarations. 1.478 + * @param c The enclosing class. 1.479 + */ 1.480 + List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) { 1.481 + ListBuffer<JCStatement> initCode = new ListBuffer<JCStatement>(); 1.482 + ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<Attribute.TypeCompound>(); 1.483 + ListBuffer<JCStatement> clinitCode = new ListBuffer<JCStatement>(); 1.484 + ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<Attribute.TypeCompound>(); 1.485 + ListBuffer<JCTree> methodDefs = new ListBuffer<JCTree>(); 1.486 + // Sort definitions into three listbuffers: 1.487 + // - initCode for instance initializers 1.488 + // - clinitCode for class initializers 1.489 + // - methodDefs for method definitions 1.490 + for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) { 1.491 + JCTree def = l.head; 1.492 + switch (def.getTag()) { 1.493 + case BLOCK: 1.494 + JCBlock block = (JCBlock)def; 1.495 + if ((block.flags & STATIC) != 0) 1.496 + clinitCode.append(block); 1.497 + else 1.498 + initCode.append(block); 1.499 + break; 1.500 + case METHODDEF: 1.501 + methodDefs.append(def); 1.502 + break; 1.503 + case VARDEF: 1.504 + JCVariableDecl vdef = (JCVariableDecl) def; 1.505 + VarSymbol sym = vdef.sym; 1.506 + checkDimension(vdef.pos(), sym.type); 1.507 + if (vdef.init != null) { 1.508 + if ((sym.flags() & STATIC) == 0) { 1.509 + // Always initialize instance variables. 1.510 + JCStatement init = make.at(vdef.pos()). 1.511 + Assignment(sym, vdef.init); 1.512 + initCode.append(init); 1.513 + endPosTable.replaceTree(vdef, init); 1.514 + initTAs.addAll(getAndRemoveNonFieldTAs(sym)); 1.515 + } else if (sym.getConstValue() == null) { 1.516 + // Initialize class (static) variables only if 1.517 + // they are not compile-time constants. 1.518 + JCStatement init = make.at(vdef.pos). 1.519 + Assignment(sym, vdef.init); 1.520 + clinitCode.append(init); 1.521 + endPosTable.replaceTree(vdef, init); 1.522 + clinitTAs.addAll(getAndRemoveNonFieldTAs(sym)); 1.523 + } else { 1.524 + checkStringConstant(vdef.init.pos(), sym.getConstValue()); 1.525 + } 1.526 + } 1.527 + break; 1.528 + default: 1.529 + Assert.error(); 1.530 + } 1.531 + } 1.532 + // Insert any instance initializers into all constructors. 1.533 + if (initCode.length() != 0) { 1.534 + List<JCStatement> inits = initCode.toList(); 1.535 + initTAs.addAll(c.getInitTypeAttributes()); 1.536 + List<Attribute.TypeCompound> initTAlist = initTAs.toList(); 1.537 + for (JCTree t : methodDefs) { 1.538 + normalizeMethod((JCMethodDecl)t, inits, initTAlist); 1.539 + } 1.540 + } 1.541 + // If there are class initializers, create a <clinit> method 1.542 + // that contains them as its body. 1.543 + if (clinitCode.length() != 0) { 1.544 + MethodSymbol clinit = new MethodSymbol( 1.545 + STATIC | (c.flags() & STRICTFP), 1.546 + names.clinit, 1.547 + new MethodType( 1.548 + List.<Type>nil(), syms.voidType, 1.549 + List.<Type>nil(), syms.methodClass), 1.550 + c); 1.551 + c.members().enter(clinit); 1.552 + List<JCStatement> clinitStats = clinitCode.toList(); 1.553 + JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats); 1.554 + block.endpos = TreeInfo.endPos(clinitStats.last()); 1.555 + methodDefs.append(make.MethodDef(clinit, block)); 1.556 + 1.557 + if (!clinitTAs.isEmpty()) 1.558 + clinit.appendUniqueTypeAttributes(clinitTAs.toList()); 1.559 + if (!c.getClassInitTypeAttributes().isEmpty()) 1.560 + clinit.appendUniqueTypeAttributes(c.getClassInitTypeAttributes()); 1.561 + } 1.562 + // Return all method definitions. 1.563 + return methodDefs.toList(); 1.564 + } 1.565 + 1.566 + private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) { 1.567 + List<TypeCompound> tas = sym.getRawTypeAttributes(); 1.568 + ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<Attribute.TypeCompound>(); 1.569 + ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<Attribute.TypeCompound>(); 1.570 + for (TypeCompound ta : tas) { 1.571 + if (ta.getPosition().type == TargetType.FIELD) { 1.572 + fieldTAs.add(ta); 1.573 + } else { 1.574 + if (typeAnnoAsserts) { 1.575 + Assert.error("Type annotation does not have a valid positior"); 1.576 + } 1.577 + 1.578 + nonfieldTAs.add(ta); 1.579 + } 1.580 + } 1.581 + sym.setTypeAttributes(fieldTAs.toList()); 1.582 + return nonfieldTAs.toList(); 1.583 + } 1.584 + 1.585 + /** Check a constant value and report if it is a string that is 1.586 + * too large. 1.587 + */ 1.588 + private void checkStringConstant(DiagnosticPosition pos, Object constValue) { 1.589 + if (nerrs != 0 || // only complain about a long string once 1.590 + constValue == null || 1.591 + !(constValue instanceof String) || 1.592 + ((String)constValue).length() < Pool.MAX_STRING_LENGTH) 1.593 + return; 1.594 + log.error(pos, "limit.string"); 1.595 + nerrs++; 1.596 + } 1.597 + 1.598 + /** Insert instance initializer code into initial constructor. 1.599 + * @param md The tree potentially representing a 1.600 + * constructor's definition. 1.601 + * @param initCode The list of instance initializer statements. 1.602 + * @param initTAs Type annotations from the initializer expression. 1.603 + */ 1.604 + void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) { 1.605 + if (md.name == names.init && TreeInfo.isInitialConstructor(md)) { 1.606 + // We are seeing a constructor that does not call another 1.607 + // constructor of the same class. 1.608 + List<JCStatement> stats = md.body.stats; 1.609 + ListBuffer<JCStatement> newstats = new ListBuffer<JCStatement>(); 1.610 + 1.611 + if (stats.nonEmpty()) { 1.612 + // Copy initializers of synthetic variables generated in 1.613 + // the translation of inner classes. 1.614 + while (TreeInfo.isSyntheticInit(stats.head)) { 1.615 + newstats.append(stats.head); 1.616 + stats = stats.tail; 1.617 + } 1.618 + // Copy superclass constructor call 1.619 + newstats.append(stats.head); 1.620 + stats = stats.tail; 1.621 + // Copy remaining synthetic initializers. 1.622 + while (stats.nonEmpty() && 1.623 + TreeInfo.isSyntheticInit(stats.head)) { 1.624 + newstats.append(stats.head); 1.625 + stats = stats.tail; 1.626 + } 1.627 + // Now insert the initializer code. 1.628 + newstats.appendList(initCode); 1.629 + // And copy all remaining statements. 1.630 + while (stats.nonEmpty()) { 1.631 + newstats.append(stats.head); 1.632 + stats = stats.tail; 1.633 + } 1.634 + } 1.635 + md.body.stats = newstats.toList(); 1.636 + if (md.body.endpos == Position.NOPOS) 1.637 + md.body.endpos = TreeInfo.endPos(md.body.stats.last()); 1.638 + 1.639 + md.sym.appendUniqueTypeAttributes(initTAs); 1.640 + } 1.641 + } 1.642 + 1.643 +/* ******************************************************************** 1.644 + * Adding miranda methods 1.645 + *********************************************************************/ 1.646 + 1.647 + /** Add abstract methods for all methods defined in one of 1.648 + * the interfaces of a given class, 1.649 + * provided they are not already implemented in the class. 1.650 + * 1.651 + * @param c The class whose interfaces are searched for methods 1.652 + * for which Miranda methods should be added. 1.653 + */ 1.654 + void implementInterfaceMethods(ClassSymbol c) { 1.655 + implementInterfaceMethods(c, c); 1.656 + } 1.657 + 1.658 + /** Add abstract methods for all methods defined in one of 1.659 + * the interfaces of a given class, 1.660 + * provided they are not already implemented in the class. 1.661 + * 1.662 + * @param c The class whose interfaces are searched for methods 1.663 + * for which Miranda methods should be added. 1.664 + * @param site The class in which a definition may be needed. 1.665 + */ 1.666 + void implementInterfaceMethods(ClassSymbol c, ClassSymbol site) { 1.667 + for (List<Type> l = types.interfaces(c.type); l.nonEmpty(); l = l.tail) { 1.668 + ClassSymbol i = (ClassSymbol)l.head.tsym; 1.669 + for (Scope.Entry e = i.members().elems; 1.670 + e != null; 1.671 + e = e.sibling) 1.672 + { 1.673 + if (e.sym.kind == MTH && (e.sym.flags() & STATIC) == 0) 1.674 + { 1.675 + MethodSymbol absMeth = (MethodSymbol)e.sym; 1.676 + MethodSymbol implMeth = absMeth.binaryImplementation(site, types); 1.677 + if (implMeth == null) 1.678 + addAbstractMethod(site, absMeth); 1.679 + else if ((implMeth.flags() & IPROXY) != 0) 1.680 + adjustAbstractMethod(site, implMeth, absMeth); 1.681 + } 1.682 + } 1.683 + implementInterfaceMethods(i, site); 1.684 + } 1.685 + } 1.686 + 1.687 + /** Add an abstract methods to a class 1.688 + * which implicitly implements a method defined in some interface 1.689 + * implemented by the class. These methods are called "Miranda methods". 1.690 + * Enter the newly created method into its enclosing class scope. 1.691 + * Note that it is not entered into the class tree, as the emitter 1.692 + * doesn't need to see it there to emit an abstract method. 1.693 + * 1.694 + * @param c The class to which the Miranda method is added. 1.695 + * @param m The interface method symbol for which a Miranda method 1.696 + * is added. 1.697 + */ 1.698 + private void addAbstractMethod(ClassSymbol c, 1.699 + MethodSymbol m) { 1.700 + MethodSymbol absMeth = new MethodSymbol( 1.701 + m.flags() | IPROXY | SYNTHETIC, m.name, 1.702 + m.type, // was c.type.memberType(m), but now only !generics supported 1.703 + c); 1.704 + c.members().enter(absMeth); // add to symbol table 1.705 + } 1.706 + 1.707 + private void adjustAbstractMethod(ClassSymbol c, 1.708 + MethodSymbol pm, 1.709 + MethodSymbol im) { 1.710 + MethodType pmt = (MethodType)pm.type; 1.711 + Type imt = types.memberType(c.type, im); 1.712 + pmt.thrown = chk.intersect(pmt.getThrownTypes(), imt.getThrownTypes()); 1.713 + } 1.714 + 1.715 +/* ************************************************************************ 1.716 + * Traversal methods 1.717 + *************************************************************************/ 1.718 + 1.719 + /** Visitor argument: The current environment. 1.720 + */ 1.721 + Env<GenContext> env; 1.722 + 1.723 + /** Visitor argument: The expected type (prototype). 1.724 + */ 1.725 + Type pt; 1.726 + 1.727 + /** Visitor result: The item representing the computed value. 1.728 + */ 1.729 + Item result; 1.730 + 1.731 + /** Visitor method: generate code for a definition, catching and reporting 1.732 + * any completion failures. 1.733 + * @param tree The definition to be visited. 1.734 + * @param env The environment current at the definition. 1.735 + */ 1.736 + public void genDef(JCTree tree, Env<GenContext> env) { 1.737 + Env<GenContext> prevEnv = this.env; 1.738 + try { 1.739 + this.env = env; 1.740 + tree.accept(this); 1.741 + } catch (CompletionFailure ex) { 1.742 + chk.completionError(tree.pos(), ex); 1.743 + } finally { 1.744 + this.env = prevEnv; 1.745 + } 1.746 + } 1.747 + 1.748 + /** Derived visitor method: check whether CharacterRangeTable 1.749 + * should be emitted, if so, put a new entry into CRTable 1.750 + * and call method to generate bytecode. 1.751 + * If not, just call method to generate bytecode. 1.752 + * @see #genStat(JCTree, Env) 1.753 + * 1.754 + * @param tree The tree to be visited. 1.755 + * @param env The environment to use. 1.756 + * @param crtFlags The CharacterRangeTable flags 1.757 + * indicating type of the entry. 1.758 + */ 1.759 + public void genStat(JCTree tree, Env<GenContext> env, int crtFlags) { 1.760 + if (!genCrt) { 1.761 + genStat(tree, env); 1.762 + return; 1.763 + } 1.764 + int startpc = code.curCP(); 1.765 + genStat(tree, env); 1.766 + if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK; 1.767 + code.crt.put(tree, crtFlags, startpc, code.curCP()); 1.768 + } 1.769 + 1.770 + /** Derived visitor method: generate code for a statement. 1.771 + */ 1.772 + public void genStat(JCTree tree, Env<GenContext> env) { 1.773 + if (code.isAlive()) { 1.774 + code.statBegin(tree.pos); 1.775 + genDef(tree, env); 1.776 + } else if (env.info.isSwitch && tree.hasTag(VARDEF)) { 1.777 + // variables whose declarations are in a switch 1.778 + // can be used even if the decl is unreachable. 1.779 + code.newLocal(((JCVariableDecl) tree).sym); 1.780 + } 1.781 + } 1.782 + 1.783 + /** Derived visitor method: check whether CharacterRangeTable 1.784 + * should be emitted, if so, put a new entry into CRTable 1.785 + * and call method to generate bytecode. 1.786 + * If not, just call method to generate bytecode. 1.787 + * @see #genStats(List, Env) 1.788 + * 1.789 + * @param trees The list of trees to be visited. 1.790 + * @param env The environment to use. 1.791 + * @param crtFlags The CharacterRangeTable flags 1.792 + * indicating type of the entry. 1.793 + */ 1.794 + public void genStats(List<JCStatement> trees, Env<GenContext> env, int crtFlags) { 1.795 + if (!genCrt) { 1.796 + genStats(trees, env); 1.797 + return; 1.798 + } 1.799 + if (trees.length() == 1) { // mark one statement with the flags 1.800 + genStat(trees.head, env, crtFlags | CRT_STATEMENT); 1.801 + } else { 1.802 + int startpc = code.curCP(); 1.803 + genStats(trees, env); 1.804 + code.crt.put(trees, crtFlags, startpc, code.curCP()); 1.805 + } 1.806 + } 1.807 + 1.808 + /** Derived visitor method: generate code for a list of statements. 1.809 + */ 1.810 + public void genStats(List<? extends JCTree> trees, Env<GenContext> env) { 1.811 + for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 1.812 + genStat(l.head, env, CRT_STATEMENT); 1.813 + } 1.814 + 1.815 + /** Derived visitor method: check whether CharacterRangeTable 1.816 + * should be emitted, if so, put a new entry into CRTable 1.817 + * and call method to generate bytecode. 1.818 + * If not, just call method to generate bytecode. 1.819 + * @see #genCond(JCTree,boolean) 1.820 + * 1.821 + * @param tree The tree to be visited. 1.822 + * @param crtFlags The CharacterRangeTable flags 1.823 + * indicating type of the entry. 1.824 + */ 1.825 + public CondItem genCond(JCTree tree, int crtFlags) { 1.826 + if (!genCrt) return genCond(tree, false); 1.827 + int startpc = code.curCP(); 1.828 + CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0); 1.829 + code.crt.put(tree, crtFlags, startpc, code.curCP()); 1.830 + return item; 1.831 + } 1.832 + 1.833 + /** Derived visitor method: generate code for a boolean 1.834 + * expression in a control-flow context. 1.835 + * @param _tree The expression to be visited. 1.836 + * @param markBranches The flag to indicate that the condition is 1.837 + * a flow controller so produced conditions 1.838 + * should contain a proper tree to generate 1.839 + * CharacterRangeTable branches for them. 1.840 + */ 1.841 + public CondItem genCond(JCTree _tree, boolean markBranches) { 1.842 + JCTree inner_tree = TreeInfo.skipParens(_tree); 1.843 + if (inner_tree.hasTag(CONDEXPR)) { 1.844 + JCConditional tree = (JCConditional)inner_tree; 1.845 + CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER); 1.846 + if (cond.isTrue()) { 1.847 + code.resolve(cond.trueJumps); 1.848 + CondItem result = genCond(tree.truepart, CRT_FLOW_TARGET); 1.849 + if (markBranches) result.tree = tree.truepart; 1.850 + return result; 1.851 + } 1.852 + if (cond.isFalse()) { 1.853 + code.resolve(cond.falseJumps); 1.854 + CondItem result = genCond(tree.falsepart, CRT_FLOW_TARGET); 1.855 + if (markBranches) result.tree = tree.falsepart; 1.856 + return result; 1.857 + } 1.858 + Chain secondJumps = cond.jumpFalse(); 1.859 + code.resolve(cond.trueJumps); 1.860 + CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET); 1.861 + if (markBranches) first.tree = tree.truepart; 1.862 + Chain falseJumps = first.jumpFalse(); 1.863 + code.resolve(first.trueJumps); 1.864 + Chain trueJumps = code.branch(goto_); 1.865 + code.resolve(secondJumps); 1.866 + CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET); 1.867 + CondItem result = items.makeCondItem(second.opcode, 1.868 + Code.mergeChains(trueJumps, second.trueJumps), 1.869 + Code.mergeChains(falseJumps, second.falseJumps)); 1.870 + if (markBranches) result.tree = tree.falsepart; 1.871 + return result; 1.872 + } else { 1.873 + CondItem result = genExpr(_tree, syms.booleanType).mkCond(); 1.874 + if (markBranches) result.tree = _tree; 1.875 + return result; 1.876 + } 1.877 + } 1.878 + 1.879 + /** Visitor class for expressions which might be constant expressions. 1.880 + * This class is a subset of TreeScanner. Intended to visit trees pruned by 1.881 + * Lower as long as constant expressions looking for references to any 1.882 + * ClassSymbol. Any such reference will be added to the constant pool so 1.883 + * automated tools can detect class dependencies better. 1.884 + */ 1.885 + class ClassReferenceVisitor extends JCTree.Visitor { 1.886 + 1.887 + @Override 1.888 + public void visitTree(JCTree tree) {} 1.889 + 1.890 + @Override 1.891 + public void visitBinary(JCBinary tree) { 1.892 + tree.lhs.accept(this); 1.893 + tree.rhs.accept(this); 1.894 + } 1.895 + 1.896 + @Override 1.897 + public void visitSelect(JCFieldAccess tree) { 1.898 + if (tree.selected.type.hasTag(CLASS)) { 1.899 + makeRef(tree.selected.pos(), tree.selected.type); 1.900 + } 1.901 + } 1.902 + 1.903 + @Override 1.904 + public void visitIdent(JCIdent tree) { 1.905 + if (tree.sym.owner instanceof ClassSymbol) { 1.906 + pool.put(tree.sym.owner); 1.907 + } 1.908 + } 1.909 + 1.910 + @Override 1.911 + public void visitConditional(JCConditional tree) { 1.912 + tree.cond.accept(this); 1.913 + tree.truepart.accept(this); 1.914 + tree.falsepart.accept(this); 1.915 + } 1.916 + 1.917 + @Override 1.918 + public void visitUnary(JCUnary tree) { 1.919 + tree.arg.accept(this); 1.920 + } 1.921 + 1.922 + @Override 1.923 + public void visitParens(JCParens tree) { 1.924 + tree.expr.accept(this); 1.925 + } 1.926 + 1.927 + @Override 1.928 + public void visitTypeCast(JCTypeCast tree) { 1.929 + tree.expr.accept(this); 1.930 + } 1.931 + } 1.932 + 1.933 + private ClassReferenceVisitor classReferenceVisitor = new ClassReferenceVisitor(); 1.934 + 1.935 + /** Visitor method: generate code for an expression, catching and reporting 1.936 + * any completion failures. 1.937 + * @param tree The expression to be visited. 1.938 + * @param pt The expression's expected type (proto-type). 1.939 + */ 1.940 + public Item genExpr(JCTree tree, Type pt) { 1.941 + Type prevPt = this.pt; 1.942 + try { 1.943 + if (tree.type.constValue() != null) { 1.944 + // Short circuit any expressions which are constants 1.945 + tree.accept(classReferenceVisitor); 1.946 + checkStringConstant(tree.pos(), tree.type.constValue()); 1.947 + result = items.makeImmediateItem(tree.type, tree.type.constValue()); 1.948 + } else { 1.949 + this.pt = pt; 1.950 + tree.accept(this); 1.951 + } 1.952 + return result.coerce(pt); 1.953 + } catch (CompletionFailure ex) { 1.954 + chk.completionError(tree.pos(), ex); 1.955 + code.state.stacksize = 1; 1.956 + return items.makeStackItem(pt); 1.957 + } finally { 1.958 + this.pt = prevPt; 1.959 + } 1.960 + } 1.961 + 1.962 + /** Derived visitor method: generate code for a list of method arguments. 1.963 + * @param trees The argument expressions to be visited. 1.964 + * @param pts The expression's expected types (i.e. the formal parameter 1.965 + * types of the invoked method). 1.966 + */ 1.967 + public void genArgs(List<JCExpression> trees, List<Type> pts) { 1.968 + for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) { 1.969 + genExpr(l.head, pts.head).load(); 1.970 + pts = pts.tail; 1.971 + } 1.972 + // require lists be of same length 1.973 + Assert.check(pts.isEmpty()); 1.974 + } 1.975 + 1.976 +/* ************************************************************************ 1.977 + * Visitor methods for statements and definitions 1.978 + *************************************************************************/ 1.979 + 1.980 + /** Thrown when the byte code size exceeds limit. 1.981 + */ 1.982 + public static class CodeSizeOverflow extends RuntimeException { 1.983 + private static final long serialVersionUID = 0; 1.984 + public CodeSizeOverflow() {} 1.985 + } 1.986 + 1.987 + public void visitMethodDef(JCMethodDecl tree) { 1.988 + // Create a new local environment that points pack at method 1.989 + // definition. 1.990 + Env<GenContext> localEnv = env.dup(tree); 1.991 + localEnv.enclMethod = tree; 1.992 + // The expected type of every return statement in this method 1.993 + // is the method's return type. 1.994 + this.pt = tree.sym.erasure(types).getReturnType(); 1.995 + 1.996 + checkDimension(tree.pos(), tree.sym.erasure(types)); 1.997 + genMethod(tree, localEnv, false); 1.998 + } 1.999 +//where 1.1000 + /** Generate code for a method. 1.1001 + * @param tree The tree representing the method definition. 1.1002 + * @param env The environment current for the method body. 1.1003 + * @param fatcode A flag that indicates whether all jumps are 1.1004 + * within 32K. We first invoke this method under 1.1005 + * the assumption that fatcode == false, i.e. all 1.1006 + * jumps are within 32K. If this fails, fatcode 1.1007 + * is set to true and we try again. 1.1008 + */ 1.1009 + void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { 1.1010 + MethodSymbol meth = tree.sym; 1.1011 + int extras = 0; 1.1012 + // Count up extra parameters 1.1013 + if (meth.isConstructor()) { 1.1014 + extras++; 1.1015 + if (meth.enclClass().isInner() && 1.1016 + !meth.enclClass().isStatic()) { 1.1017 + extras++; 1.1018 + } 1.1019 + } else if ((tree.mods.flags & STATIC) == 0) { 1.1020 + extras++; 1.1021 + } 1.1022 + // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG 1.1023 + if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras > 1.1024 + ClassFile.MAX_PARAMETERS) { 1.1025 + log.error(tree.pos(), "limit.parameters"); 1.1026 + nerrs++; 1.1027 + } 1.1028 + 1.1029 + else if (tree.body != null) { 1.1030 + // Create a new code structure and initialize it. 1.1031 + int startpcCrt = initCode(tree, env, fatcode); 1.1032 + 1.1033 + try { 1.1034 + genStat(tree.body, env); 1.1035 + } catch (CodeSizeOverflow e) { 1.1036 + // Failed due to code limit, try again with jsr/ret 1.1037 + startpcCrt = initCode(tree, env, fatcode); 1.1038 + genStat(tree.body, env); 1.1039 + } 1.1040 + 1.1041 + if (code.state.stacksize != 0) { 1.1042 + log.error(tree.body.pos(), "stack.sim.error", tree); 1.1043 + throw new AssertionError(); 1.1044 + } 1.1045 + 1.1046 + // If last statement could complete normally, insert a 1.1047 + // return at the end. 1.1048 + if (code.isAlive()) { 1.1049 + code.statBegin(TreeInfo.endPos(tree.body)); 1.1050 + if (env.enclMethod == null || 1.1051 + env.enclMethod.sym.type.getReturnType().hasTag(VOID)) { 1.1052 + code.emitop0(return_); 1.1053 + } else { 1.1054 + // sometime dead code seems alive (4415991); 1.1055 + // generate a small loop instead 1.1056 + int startpc = code.entryPoint(); 1.1057 + CondItem c = items.makeCondItem(goto_); 1.1058 + code.resolve(c.jumpTrue(), startpc); 1.1059 + } 1.1060 + } 1.1061 + if (genCrt) 1.1062 + code.crt.put(tree.body, 1.1063 + CRT_BLOCK, 1.1064 + startpcCrt, 1.1065 + code.curCP()); 1.1066 + 1.1067 + code.endScopes(0); 1.1068 + 1.1069 + // If we exceeded limits, panic 1.1070 + if (code.checkLimits(tree.pos(), log)) { 1.1071 + nerrs++; 1.1072 + return; 1.1073 + } 1.1074 + 1.1075 + // If we generated short code but got a long jump, do it again 1.1076 + // with fatCode = true. 1.1077 + if (!fatcode && code.fatcode) genMethod(tree, env, true); 1.1078 + 1.1079 + // Clean up 1.1080 + if(stackMap == StackMapFormat.JSR202) { 1.1081 + code.lastFrame = null; 1.1082 + code.frameBeforeLast = null; 1.1083 + } 1.1084 + 1.1085 + // Compress exception table 1.1086 + code.compressCatchTable(); 1.1087 + 1.1088 + // Fill in type annotation positions for exception parameters 1.1089 + code.fillExceptionParameterPositions(); 1.1090 + } 1.1091 + } 1.1092 + 1.1093 + private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { 1.1094 + MethodSymbol meth = tree.sym; 1.1095 + 1.1096 + // Create a new code structure. 1.1097 + meth.code = code = new Code(meth, 1.1098 + fatcode, 1.1099 + lineDebugInfo ? toplevel.lineMap : null, 1.1100 + varDebugInfo, 1.1101 + stackMap, 1.1102 + debugCode, 1.1103 + genCrt ? new CRTable(tree, env.toplevel.endPositions) 1.1104 + : null, 1.1105 + syms, 1.1106 + types, 1.1107 + pool, 1.1108 + varDebugInfo ? lvtRanges : null); 1.1109 + items = new Items(pool, code, syms, types); 1.1110 + if (code.debugCode) { 1.1111 + System.err.println(meth + " for body " + tree); 1.1112 + } 1.1113 + 1.1114 + // If method is not static, create a new local variable address 1.1115 + // for `this'. 1.1116 + if ((tree.mods.flags & STATIC) == 0) { 1.1117 + Type selfType = meth.owner.type; 1.1118 + if (meth.isConstructor() && selfType != syms.objectType) 1.1119 + selfType = UninitializedType.uninitializedThis(selfType); 1.1120 + code.setDefined( 1.1121 + code.newLocal( 1.1122 + new VarSymbol(FINAL, names._this, selfType, meth.owner))); 1.1123 + } 1.1124 + 1.1125 + // Mark all parameters as defined from the beginning of 1.1126 + // the method. 1.1127 + for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 1.1128 + checkDimension(l.head.pos(), l.head.sym.type); 1.1129 + code.setDefined(code.newLocal(l.head.sym)); 1.1130 + } 1.1131 + 1.1132 + // Get ready to generate code for method body. 1.1133 + int startpcCrt = genCrt ? code.curCP() : 0; 1.1134 + code.entryPoint(); 1.1135 + 1.1136 + // Suppress initial stackmap 1.1137 + code.pendingStackMap = false; 1.1138 + 1.1139 + return startpcCrt; 1.1140 + } 1.1141 + 1.1142 + public void visitVarDef(JCVariableDecl tree) { 1.1143 + VarSymbol v = tree.sym; 1.1144 + code.newLocal(v); 1.1145 + if (tree.init != null) { 1.1146 + checkStringConstant(tree.init.pos(), v.getConstValue()); 1.1147 + if (v.getConstValue() == null || varDebugInfo) { 1.1148 + genExpr(tree.init, v.erasure(types)).load(); 1.1149 + items.makeLocalItem(v).store(); 1.1150 + } 1.1151 + } 1.1152 + checkDimension(tree.pos(), v.type); 1.1153 + } 1.1154 + 1.1155 + public void visitSkip(JCSkip tree) { 1.1156 + } 1.1157 + 1.1158 + public void visitBlock(JCBlock tree) { 1.1159 + int limit = code.nextreg; 1.1160 + Env<GenContext> localEnv = env.dup(tree, new GenContext()); 1.1161 + genStats(tree.stats, localEnv); 1.1162 + // End the scope of all block-local variables in variable info. 1.1163 + if (!env.tree.hasTag(METHODDEF)) { 1.1164 + code.statBegin(tree.endpos); 1.1165 + code.endScopes(limit); 1.1166 + code.pendingStatPos = Position.NOPOS; 1.1167 + } 1.1168 + } 1.1169 + 1.1170 + public void visitDoLoop(JCDoWhileLoop tree) { 1.1171 + genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), false); 1.1172 + } 1.1173 + 1.1174 + public void visitWhileLoop(JCWhileLoop tree) { 1.1175 + genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), true); 1.1176 + } 1.1177 + 1.1178 + public void visitForLoop(JCForLoop tree) { 1.1179 + int limit = code.nextreg; 1.1180 + genStats(tree.init, env); 1.1181 + genLoop(tree, tree.body, tree.cond, tree.step, true); 1.1182 + code.endScopes(limit); 1.1183 + } 1.1184 + //where 1.1185 + /** Generate code for a loop. 1.1186 + * @param loop The tree representing the loop. 1.1187 + * @param body The loop's body. 1.1188 + * @param cond The loop's controling condition. 1.1189 + * @param step "Step" statements to be inserted at end of 1.1190 + * each iteration. 1.1191 + * @param testFirst True if the loop test belongs before the body. 1.1192 + */ 1.1193 + private void genLoop(JCStatement loop, 1.1194 + JCStatement body, 1.1195 + JCExpression cond, 1.1196 + List<JCExpressionStatement> step, 1.1197 + boolean testFirst) { 1.1198 + Env<GenContext> loopEnv = env.dup(loop, new GenContext()); 1.1199 + int startpc = code.entryPoint(); 1.1200 + if (testFirst) { 1.1201 + CondItem c; 1.1202 + if (cond != null) { 1.1203 + code.statBegin(cond.pos); 1.1204 + c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); 1.1205 + } else { 1.1206 + c = items.makeCondItem(goto_); 1.1207 + } 1.1208 + Chain loopDone = c.jumpFalse(); 1.1209 + code.resolve(c.trueJumps); 1.1210 + genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); 1.1211 + if (varDebugInfo) { 1.1212 + checkLoopLocalVarRangeEnding(loop, body, 1.1213 + LoopLocalVarRangeEndingPoint.BEFORE_STEPS); 1.1214 + } 1.1215 + code.resolve(loopEnv.info.cont); 1.1216 + genStats(step, loopEnv); 1.1217 + if (varDebugInfo) { 1.1218 + checkLoopLocalVarRangeEnding(loop, body, 1.1219 + LoopLocalVarRangeEndingPoint.AFTER_STEPS); 1.1220 + } 1.1221 + code.resolve(code.branch(goto_), startpc); 1.1222 + code.resolve(loopDone); 1.1223 + } else { 1.1224 + genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); 1.1225 + if (varDebugInfo) { 1.1226 + checkLoopLocalVarRangeEnding(loop, body, 1.1227 + LoopLocalVarRangeEndingPoint.BEFORE_STEPS); 1.1228 + } 1.1229 + code.resolve(loopEnv.info.cont); 1.1230 + genStats(step, loopEnv); 1.1231 + if (varDebugInfo) { 1.1232 + checkLoopLocalVarRangeEnding(loop, body, 1.1233 + LoopLocalVarRangeEndingPoint.AFTER_STEPS); 1.1234 + } 1.1235 + CondItem c; 1.1236 + if (cond != null) { 1.1237 + code.statBegin(cond.pos); 1.1238 + c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); 1.1239 + } else { 1.1240 + c = items.makeCondItem(goto_); 1.1241 + } 1.1242 + code.resolve(c.jumpTrue(), startpc); 1.1243 + code.resolve(c.falseJumps); 1.1244 + } 1.1245 + code.resolve(loopEnv.info.exit); 1.1246 + } 1.1247 + 1.1248 + private enum LoopLocalVarRangeEndingPoint { 1.1249 + BEFORE_STEPS, 1.1250 + AFTER_STEPS, 1.1251 + } 1.1252 + 1.1253 + /** 1.1254 + * Checks whether we have reached an alive range ending point for local 1.1255 + * variables after a loop. 1.1256 + * 1.1257 + * Local variables alive range ending point for loops varies depending 1.1258 + * on the loop type. The range can be closed before or after the code 1.1259 + * for the steps sentences has been generated. 1.1260 + * 1.1261 + * - While loops has no steps so in that case the range is closed just 1.1262 + * after the body of the loop. 1.1263 + * 1.1264 + * - For-like loops may have steps so as long as the steps sentences 1.1265 + * can possibly contain non-synthetic local variables, the alive range 1.1266 + * for local variables must be closed after the steps in this case. 1.1267 + */ 1.1268 + private void checkLoopLocalVarRangeEnding(JCTree loop, JCTree body, 1.1269 + LoopLocalVarRangeEndingPoint endingPoint) { 1.1270 + if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) { 1.1271 + switch (endingPoint) { 1.1272 + case BEFORE_STEPS: 1.1273 + if (!loop.hasTag(FORLOOP)) { 1.1274 + code.closeAliveRanges(body); 1.1275 + } 1.1276 + break; 1.1277 + case AFTER_STEPS: 1.1278 + if (loop.hasTag(FORLOOP)) { 1.1279 + code.closeAliveRanges(body); 1.1280 + } 1.1281 + break; 1.1282 + } 1.1283 + } 1.1284 + } 1.1285 + 1.1286 + public void visitForeachLoop(JCEnhancedForLoop tree) { 1.1287 + throw new AssertionError(); // should have been removed by Lower. 1.1288 + } 1.1289 + 1.1290 + public void visitLabelled(JCLabeledStatement tree) { 1.1291 + Env<GenContext> localEnv = env.dup(tree, new GenContext()); 1.1292 + genStat(tree.body, localEnv, CRT_STATEMENT); 1.1293 + code.resolve(localEnv.info.exit); 1.1294 + } 1.1295 + 1.1296 + public void visitSwitch(JCSwitch tree) { 1.1297 + int limit = code.nextreg; 1.1298 + Assert.check(!tree.selector.type.hasTag(CLASS)); 1.1299 + int startpcCrt = genCrt ? code.curCP() : 0; 1.1300 + Item sel = genExpr(tree.selector, syms.intType); 1.1301 + List<JCCase> cases = tree.cases; 1.1302 + if (cases.isEmpty()) { 1.1303 + // We are seeing: switch <sel> {} 1.1304 + sel.load().drop(); 1.1305 + if (genCrt) 1.1306 + code.crt.put(TreeInfo.skipParens(tree.selector), 1.1307 + CRT_FLOW_CONTROLLER, startpcCrt, code.curCP()); 1.1308 + } else { 1.1309 + // We are seeing a nonempty switch. 1.1310 + sel.load(); 1.1311 + if (genCrt) 1.1312 + code.crt.put(TreeInfo.skipParens(tree.selector), 1.1313 + CRT_FLOW_CONTROLLER, startpcCrt, code.curCP()); 1.1314 + Env<GenContext> switchEnv = env.dup(tree, new GenContext()); 1.1315 + switchEnv.info.isSwitch = true; 1.1316 + 1.1317 + // Compute number of labels and minimum and maximum label values. 1.1318 + // For each case, store its label in an array. 1.1319 + int lo = Integer.MAX_VALUE; // minimum label. 1.1320 + int hi = Integer.MIN_VALUE; // maximum label. 1.1321 + int nlabels = 0; // number of labels. 1.1322 + 1.1323 + int[] labels = new int[cases.length()]; // the label array. 1.1324 + int defaultIndex = -1; // the index of the default clause. 1.1325 + 1.1326 + List<JCCase> l = cases; 1.1327 + for (int i = 0; i < labels.length; i++) { 1.1328 + if (l.head.pat != null) { 1.1329 + int val = ((Number)l.head.pat.type.constValue()).intValue(); 1.1330 + labels[i] = val; 1.1331 + if (val < lo) lo = val; 1.1332 + if (hi < val) hi = val; 1.1333 + nlabels++; 1.1334 + } else { 1.1335 + Assert.check(defaultIndex == -1); 1.1336 + defaultIndex = i; 1.1337 + } 1.1338 + l = l.tail; 1.1339 + } 1.1340 + 1.1341 + // Determine whether to issue a tableswitch or a lookupswitch 1.1342 + // instruction. 1.1343 + long table_space_cost = 4 + ((long) hi - lo + 1); // words 1.1344 + long table_time_cost = 3; // comparisons 1.1345 + long lookup_space_cost = 3 + 2 * (long) nlabels; 1.1346 + long lookup_time_cost = nlabels; 1.1347 + int opcode = 1.1348 + nlabels > 0 && 1.1349 + table_space_cost + 3 * table_time_cost <= 1.1350 + lookup_space_cost + 3 * lookup_time_cost 1.1351 + ? 1.1352 + tableswitch : lookupswitch; 1.1353 + 1.1354 + int startpc = code.curCP(); // the position of the selector operation 1.1355 + code.emitop0(opcode); 1.1356 + code.align(4); 1.1357 + int tableBase = code.curCP(); // the start of the jump table 1.1358 + int[] offsets = null; // a table of offsets for a lookupswitch 1.1359 + code.emit4(-1); // leave space for default offset 1.1360 + if (opcode == tableswitch) { 1.1361 + code.emit4(lo); // minimum label 1.1362 + code.emit4(hi); // maximum label 1.1363 + for (long i = lo; i <= hi; i++) { // leave space for jump table 1.1364 + code.emit4(-1); 1.1365 + } 1.1366 + } else { 1.1367 + code.emit4(nlabels); // number of labels 1.1368 + for (int i = 0; i < nlabels; i++) { 1.1369 + code.emit4(-1); code.emit4(-1); // leave space for lookup table 1.1370 + } 1.1371 + offsets = new int[labels.length]; 1.1372 + } 1.1373 + Code.State stateSwitch = code.state.dup(); 1.1374 + code.markDead(); 1.1375 + 1.1376 + // For each case do: 1.1377 + l = cases; 1.1378 + for (int i = 0; i < labels.length; i++) { 1.1379 + JCCase c = l.head; 1.1380 + l = l.tail; 1.1381 + 1.1382 + int pc = code.entryPoint(stateSwitch); 1.1383 + // Insert offset directly into code or else into the 1.1384 + // offsets table. 1.1385 + if (i != defaultIndex) { 1.1386 + if (opcode == tableswitch) { 1.1387 + code.put4( 1.1388 + tableBase + 4 * (labels[i] - lo + 3), 1.1389 + pc - startpc); 1.1390 + } else { 1.1391 + offsets[i] = pc - startpc; 1.1392 + } 1.1393 + } else { 1.1394 + code.put4(tableBase, pc - startpc); 1.1395 + } 1.1396 + 1.1397 + // Generate code for the statements in this case. 1.1398 + genStats(c.stats, switchEnv, CRT_FLOW_TARGET); 1.1399 + if (varDebugInfo && lvtRanges.containsKey(code.meth, c.stats.last())) { 1.1400 + code.closeAliveRanges(c.stats.last()); 1.1401 + } 1.1402 + } 1.1403 + 1.1404 + // Resolve all breaks. 1.1405 + code.resolve(switchEnv.info.exit); 1.1406 + 1.1407 + // If we have not set the default offset, we do so now. 1.1408 + if (code.get4(tableBase) == -1) { 1.1409 + code.put4(tableBase, code.entryPoint(stateSwitch) - startpc); 1.1410 + } 1.1411 + 1.1412 + if (opcode == tableswitch) { 1.1413 + // Let any unfilled slots point to the default case. 1.1414 + int defaultOffset = code.get4(tableBase); 1.1415 + for (long i = lo; i <= hi; i++) { 1.1416 + int t = (int)(tableBase + 4 * (i - lo + 3)); 1.1417 + if (code.get4(t) == -1) 1.1418 + code.put4(t, defaultOffset); 1.1419 + } 1.1420 + } else { 1.1421 + // Sort non-default offsets and copy into lookup table. 1.1422 + if (defaultIndex >= 0) 1.1423 + for (int i = defaultIndex; i < labels.length - 1; i++) { 1.1424 + labels[i] = labels[i+1]; 1.1425 + offsets[i] = offsets[i+1]; 1.1426 + } 1.1427 + if (nlabels > 0) 1.1428 + qsort2(labels, offsets, 0, nlabels - 1); 1.1429 + for (int i = 0; i < nlabels; i++) { 1.1430 + int caseidx = tableBase + 8 * (i + 1); 1.1431 + code.put4(caseidx, labels[i]); 1.1432 + code.put4(caseidx + 4, offsets[i]); 1.1433 + } 1.1434 + } 1.1435 + } 1.1436 + code.endScopes(limit); 1.1437 + } 1.1438 +//where 1.1439 + /** Sort (int) arrays of keys and values 1.1440 + */ 1.1441 + static void qsort2(int[] keys, int[] values, int lo, int hi) { 1.1442 + int i = lo; 1.1443 + int j = hi; 1.1444 + int pivot = keys[(i+j)/2]; 1.1445 + do { 1.1446 + while (keys[i] < pivot) i++; 1.1447 + while (pivot < keys[j]) j--; 1.1448 + if (i <= j) { 1.1449 + int temp1 = keys[i]; 1.1450 + keys[i] = keys[j]; 1.1451 + keys[j] = temp1; 1.1452 + int temp2 = values[i]; 1.1453 + values[i] = values[j]; 1.1454 + values[j] = temp2; 1.1455 + i++; 1.1456 + j--; 1.1457 + } 1.1458 + } while (i <= j); 1.1459 + if (lo < j) qsort2(keys, values, lo, j); 1.1460 + if (i < hi) qsort2(keys, values, i, hi); 1.1461 + } 1.1462 + 1.1463 + public void visitSynchronized(JCSynchronized tree) { 1.1464 + int limit = code.nextreg; 1.1465 + // Generate code to evaluate lock and save in temporary variable. 1.1466 + final LocalItem lockVar = makeTemp(syms.objectType); 1.1467 + genExpr(tree.lock, tree.lock.type).load().duplicate(); 1.1468 + lockVar.store(); 1.1469 + 1.1470 + // Generate code to enter monitor. 1.1471 + code.emitop0(monitorenter); 1.1472 + code.state.lock(lockVar.reg); 1.1473 + 1.1474 + // Generate code for a try statement with given body, no catch clauses 1.1475 + // in a new environment with the "exit-monitor" operation as finalizer. 1.1476 + final Env<GenContext> syncEnv = env.dup(tree, new GenContext()); 1.1477 + syncEnv.info.finalize = new GenFinalizer() { 1.1478 + void gen() { 1.1479 + genLast(); 1.1480 + Assert.check(syncEnv.info.gaps.length() % 2 == 0); 1.1481 + syncEnv.info.gaps.append(code.curCP()); 1.1482 + } 1.1483 + void genLast() { 1.1484 + if (code.isAlive()) { 1.1485 + lockVar.load(); 1.1486 + code.emitop0(monitorexit); 1.1487 + code.state.unlock(lockVar.reg); 1.1488 + } 1.1489 + } 1.1490 + }; 1.1491 + syncEnv.info.gaps = new ListBuffer<Integer>(); 1.1492 + genTry(tree.body, List.<JCCatch>nil(), syncEnv); 1.1493 + code.endScopes(limit); 1.1494 + } 1.1495 + 1.1496 + public void visitTry(final JCTry tree) { 1.1497 + // Generate code for a try statement with given body and catch clauses, 1.1498 + // in a new environment which calls the finally block if there is one. 1.1499 + final Env<GenContext> tryEnv = env.dup(tree, new GenContext()); 1.1500 + final Env<GenContext> oldEnv = env; 1.1501 + if (!useJsrLocally) { 1.1502 + useJsrLocally = 1.1503 + (stackMap == StackMapFormat.NONE) && 1.1504 + (jsrlimit <= 0 || 1.1505 + jsrlimit < 100 && 1.1506 + estimateCodeComplexity(tree.finalizer)>jsrlimit); 1.1507 + } 1.1508 + tryEnv.info.finalize = new GenFinalizer() { 1.1509 + void gen() { 1.1510 + if (useJsrLocally) { 1.1511 + if (tree.finalizer != null) { 1.1512 + Code.State jsrState = code.state.dup(); 1.1513 + jsrState.push(Code.jsrReturnValue); 1.1514 + tryEnv.info.cont = 1.1515 + new Chain(code.emitJump(jsr), 1.1516 + tryEnv.info.cont, 1.1517 + jsrState); 1.1518 + } 1.1519 + Assert.check(tryEnv.info.gaps.length() % 2 == 0); 1.1520 + tryEnv.info.gaps.append(code.curCP()); 1.1521 + } else { 1.1522 + Assert.check(tryEnv.info.gaps.length() % 2 == 0); 1.1523 + tryEnv.info.gaps.append(code.curCP()); 1.1524 + genLast(); 1.1525 + } 1.1526 + } 1.1527 + void genLast() { 1.1528 + if (tree.finalizer != null) 1.1529 + genStat(tree.finalizer, oldEnv, CRT_BLOCK); 1.1530 + } 1.1531 + boolean hasFinalizer() { 1.1532 + return tree.finalizer != null; 1.1533 + } 1.1534 + }; 1.1535 + tryEnv.info.gaps = new ListBuffer<Integer>(); 1.1536 + genTry(tree.body, tree.catchers, tryEnv); 1.1537 + } 1.1538 + //where 1.1539 + /** Generate code for a try or synchronized statement 1.1540 + * @param body The body of the try or synchronized statement. 1.1541 + * @param catchers The lis of catch clauses. 1.1542 + * @param env the environment current for the body. 1.1543 + */ 1.1544 + void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) { 1.1545 + int limit = code.nextreg; 1.1546 + int startpc = code.curCP(); 1.1547 + Code.State stateTry = code.state.dup(); 1.1548 + genStat(body, env, CRT_BLOCK); 1.1549 + int endpc = code.curCP(); 1.1550 + boolean hasFinalizer = 1.1551 + env.info.finalize != null && 1.1552 + env.info.finalize.hasFinalizer(); 1.1553 + List<Integer> gaps = env.info.gaps.toList(); 1.1554 + code.statBegin(TreeInfo.endPos(body)); 1.1555 + genFinalizer(env); 1.1556 + code.statBegin(TreeInfo.endPos(env.tree)); 1.1557 + Chain exitChain = code.branch(goto_); 1.1558 + if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) { 1.1559 + code.closeAliveRanges(body); 1.1560 + } 1.1561 + endFinalizerGap(env); 1.1562 + if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) { 1.1563 + // start off with exception on stack 1.1564 + code.entryPoint(stateTry, l.head.param.sym.type); 1.1565 + genCatch(l.head, env, startpc, endpc, gaps); 1.1566 + genFinalizer(env); 1.1567 + if (hasFinalizer || l.tail.nonEmpty()) { 1.1568 + code.statBegin(TreeInfo.endPos(env.tree)); 1.1569 + exitChain = Code.mergeChains(exitChain, 1.1570 + code.branch(goto_)); 1.1571 + } 1.1572 + endFinalizerGap(env); 1.1573 + } 1.1574 + if (hasFinalizer) { 1.1575 + // Create a new register segement to avoid allocating 1.1576 + // the same variables in finalizers and other statements. 1.1577 + code.newRegSegment(); 1.1578 + 1.1579 + // Add a catch-all clause. 1.1580 + 1.1581 + // start off with exception on stack 1.1582 + int catchallpc = code.entryPoint(stateTry, syms.throwableType); 1.1583 + 1.1584 + // Register all exception ranges for catch all clause. 1.1585 + // The range of the catch all clause is from the beginning 1.1586 + // of the try or synchronized block until the present 1.1587 + // code pointer excluding all gaps in the current 1.1588 + // environment's GenContext. 1.1589 + int startseg = startpc; 1.1590 + while (env.info.gaps.nonEmpty()) { 1.1591 + int endseg = env.info.gaps.next().intValue(); 1.1592 + registerCatch(body.pos(), startseg, endseg, 1.1593 + catchallpc, 0); 1.1594 + startseg = env.info.gaps.next().intValue(); 1.1595 + } 1.1596 + code.statBegin(TreeInfo.finalizerPos(env.tree)); 1.1597 + code.markStatBegin(); 1.1598 + 1.1599 + Item excVar = makeTemp(syms.throwableType); 1.1600 + excVar.store(); 1.1601 + genFinalizer(env); 1.1602 + excVar.load(); 1.1603 + registerCatch(body.pos(), startseg, 1.1604 + env.info.gaps.next().intValue(), 1.1605 + catchallpc, 0); 1.1606 + code.emitop0(athrow); 1.1607 + code.markDead(); 1.1608 + 1.1609 + // If there are jsr's to this finalizer, ... 1.1610 + if (env.info.cont != null) { 1.1611 + // Resolve all jsr's. 1.1612 + code.resolve(env.info.cont); 1.1613 + 1.1614 + // Mark statement line number 1.1615 + code.statBegin(TreeInfo.finalizerPos(env.tree)); 1.1616 + code.markStatBegin(); 1.1617 + 1.1618 + // Save return address. 1.1619 + LocalItem retVar = makeTemp(syms.throwableType); 1.1620 + retVar.store(); 1.1621 + 1.1622 + // Generate finalizer code. 1.1623 + env.info.finalize.genLast(); 1.1624 + 1.1625 + // Return. 1.1626 + code.emitop1w(ret, retVar.reg); 1.1627 + code.markDead(); 1.1628 + } 1.1629 + } 1.1630 + // Resolve all breaks. 1.1631 + code.resolve(exitChain); 1.1632 + 1.1633 + code.endScopes(limit); 1.1634 + } 1.1635 + 1.1636 + /** Generate code for a catch clause. 1.1637 + * @param tree The catch clause. 1.1638 + * @param env The environment current in the enclosing try. 1.1639 + * @param startpc Start pc of try-block. 1.1640 + * @param endpc End pc of try-block. 1.1641 + */ 1.1642 + void genCatch(JCCatch tree, 1.1643 + Env<GenContext> env, 1.1644 + int startpc, int endpc, 1.1645 + List<Integer> gaps) { 1.1646 + if (startpc != endpc) { 1.1647 + List<JCExpression> subClauses = TreeInfo.isMultiCatch(tree) ? 1.1648 + ((JCTypeUnion)tree.param.vartype).alternatives : 1.1649 + List.of(tree.param.vartype); 1.1650 + while (gaps.nonEmpty()) { 1.1651 + for (JCExpression subCatch : subClauses) { 1.1652 + int catchType = makeRef(tree.pos(), subCatch.type); 1.1653 + int end = gaps.head.intValue(); 1.1654 + registerCatch(tree.pos(), 1.1655 + startpc, end, code.curCP(), 1.1656 + catchType); 1.1657 + if (subCatch.type.isAnnotated()) { 1.1658 + for (Attribute.TypeCompound tc : 1.1659 + subCatch.type.getAnnotationMirrors()) { 1.1660 + tc.position.type_index = catchType; 1.1661 + } 1.1662 + } 1.1663 + } 1.1664 + gaps = gaps.tail; 1.1665 + startpc = gaps.head.intValue(); 1.1666 + gaps = gaps.tail; 1.1667 + } 1.1668 + if (startpc < endpc) { 1.1669 + for (JCExpression subCatch : subClauses) { 1.1670 + int catchType = makeRef(tree.pos(), subCatch.type); 1.1671 + registerCatch(tree.pos(), 1.1672 + startpc, endpc, code.curCP(), 1.1673 + catchType); 1.1674 + if (subCatch.type.isAnnotated()) { 1.1675 + for (Attribute.TypeCompound tc : 1.1676 + subCatch.type.getAnnotationMirrors()) { 1.1677 + tc.position.type_index = catchType; 1.1678 + } 1.1679 + } 1.1680 + } 1.1681 + } 1.1682 + VarSymbol exparam = tree.param.sym; 1.1683 + code.statBegin(tree.pos); 1.1684 + code.markStatBegin(); 1.1685 + int limit = code.nextreg; 1.1686 + int exlocal = code.newLocal(exparam); 1.1687 + items.makeLocalItem(exparam).store(); 1.1688 + code.statBegin(TreeInfo.firstStatPos(tree.body)); 1.1689 + genStat(tree.body, env, CRT_BLOCK); 1.1690 + code.endScopes(limit); 1.1691 + code.statBegin(TreeInfo.endPos(tree.body)); 1.1692 + } 1.1693 + } 1.1694 + 1.1695 + /** Register a catch clause in the "Exceptions" code-attribute. 1.1696 + */ 1.1697 + void registerCatch(DiagnosticPosition pos, 1.1698 + int startpc, int endpc, 1.1699 + int handler_pc, int catch_type) { 1.1700 + char startpc1 = (char)startpc; 1.1701 + char endpc1 = (char)endpc; 1.1702 + char handler_pc1 = (char)handler_pc; 1.1703 + if (startpc1 == startpc && 1.1704 + endpc1 == endpc && 1.1705 + handler_pc1 == handler_pc) { 1.1706 + code.addCatch(startpc1, endpc1, handler_pc1, 1.1707 + (char)catch_type); 1.1708 + } else { 1.1709 + if (!useJsrLocally && !target.generateStackMapTable()) { 1.1710 + useJsrLocally = true; 1.1711 + throw new CodeSizeOverflow(); 1.1712 + } else { 1.1713 + log.error(pos, "limit.code.too.large.for.try.stmt"); 1.1714 + nerrs++; 1.1715 + } 1.1716 + } 1.1717 + } 1.1718 + 1.1719 + /** Very roughly estimate the number of instructions needed for 1.1720 + * the given tree. 1.1721 + */ 1.1722 + int estimateCodeComplexity(JCTree tree) { 1.1723 + if (tree == null) return 0; 1.1724 + class ComplexityScanner extends TreeScanner { 1.1725 + int complexity = 0; 1.1726 + public void scan(JCTree tree) { 1.1727 + if (complexity > jsrlimit) return; 1.1728 + super.scan(tree); 1.1729 + } 1.1730 + public void visitClassDef(JCClassDecl tree) {} 1.1731 + public void visitDoLoop(JCDoWhileLoop tree) 1.1732 + { super.visitDoLoop(tree); complexity++; } 1.1733 + public void visitWhileLoop(JCWhileLoop tree) 1.1734 + { super.visitWhileLoop(tree); complexity++; } 1.1735 + public void visitForLoop(JCForLoop tree) 1.1736 + { super.visitForLoop(tree); complexity++; } 1.1737 + public void visitSwitch(JCSwitch tree) 1.1738 + { super.visitSwitch(tree); complexity+=5; } 1.1739 + public void visitCase(JCCase tree) 1.1740 + { super.visitCase(tree); complexity++; } 1.1741 + public void visitSynchronized(JCSynchronized tree) 1.1742 + { super.visitSynchronized(tree); complexity+=6; } 1.1743 + public void visitTry(JCTry tree) 1.1744 + { super.visitTry(tree); 1.1745 + if (tree.finalizer != null) complexity+=6; } 1.1746 + public void visitCatch(JCCatch tree) 1.1747 + { super.visitCatch(tree); complexity+=2; } 1.1748 + public void visitConditional(JCConditional tree) 1.1749 + { super.visitConditional(tree); complexity+=2; } 1.1750 + public void visitIf(JCIf tree) 1.1751 + { super.visitIf(tree); complexity+=2; } 1.1752 + // note: for break, continue, and return we don't take unwind() into account. 1.1753 + public void visitBreak(JCBreak tree) 1.1754 + { super.visitBreak(tree); complexity+=1; } 1.1755 + public void visitContinue(JCContinue tree) 1.1756 + { super.visitContinue(tree); complexity+=1; } 1.1757 + public void visitReturn(JCReturn tree) 1.1758 + { super.visitReturn(tree); complexity+=1; } 1.1759 + public void visitThrow(JCThrow tree) 1.1760 + { super.visitThrow(tree); complexity+=1; } 1.1761 + public void visitAssert(JCAssert tree) 1.1762 + { super.visitAssert(tree); complexity+=5; } 1.1763 + public void visitApply(JCMethodInvocation tree) 1.1764 + { super.visitApply(tree); complexity+=2; } 1.1765 + public void visitNewClass(JCNewClass tree) 1.1766 + { scan(tree.encl); scan(tree.args); complexity+=2; } 1.1767 + public void visitNewArray(JCNewArray tree) 1.1768 + { super.visitNewArray(tree); complexity+=5; } 1.1769 + public void visitAssign(JCAssign tree) 1.1770 + { super.visitAssign(tree); complexity+=1; } 1.1771 + public void visitAssignop(JCAssignOp tree) 1.1772 + { super.visitAssignop(tree); complexity+=2; } 1.1773 + public void visitUnary(JCUnary tree) 1.1774 + { complexity+=1; 1.1775 + if (tree.type.constValue() == null) super.visitUnary(tree); } 1.1776 + public void visitBinary(JCBinary tree) 1.1777 + { complexity+=1; 1.1778 + if (tree.type.constValue() == null) super.visitBinary(tree); } 1.1779 + public void visitTypeTest(JCInstanceOf tree) 1.1780 + { super.visitTypeTest(tree); complexity+=1; } 1.1781 + public void visitIndexed(JCArrayAccess tree) 1.1782 + { super.visitIndexed(tree); complexity+=1; } 1.1783 + public void visitSelect(JCFieldAccess tree) 1.1784 + { super.visitSelect(tree); 1.1785 + if (tree.sym.kind == VAR) complexity+=1; } 1.1786 + public void visitIdent(JCIdent tree) { 1.1787 + if (tree.sym.kind == VAR) { 1.1788 + complexity+=1; 1.1789 + if (tree.type.constValue() == null && 1.1790 + tree.sym.owner.kind == TYP) 1.1791 + complexity+=1; 1.1792 + } 1.1793 + } 1.1794 + public void visitLiteral(JCLiteral tree) 1.1795 + { complexity+=1; } 1.1796 + public void visitTree(JCTree tree) {} 1.1797 + public void visitWildcard(JCWildcard tree) { 1.1798 + throw new AssertionError(this.getClass().getName()); 1.1799 + } 1.1800 + } 1.1801 + ComplexityScanner scanner = new ComplexityScanner(); 1.1802 + tree.accept(scanner); 1.1803 + return scanner.complexity; 1.1804 + } 1.1805 + 1.1806 + public void visitIf(JCIf tree) { 1.1807 + int limit = code.nextreg; 1.1808 + Chain thenExit = null; 1.1809 + CondItem c = genCond(TreeInfo.skipParens(tree.cond), 1.1810 + CRT_FLOW_CONTROLLER); 1.1811 + Chain elseChain = c.jumpFalse(); 1.1812 + if (!c.isFalse()) { 1.1813 + code.resolve(c.trueJumps); 1.1814 + genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET); 1.1815 + thenExit = code.branch(goto_); 1.1816 + if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.thenpart)) { 1.1817 + code.closeAliveRanges(tree.thenpart, code.cp); 1.1818 + } 1.1819 + } 1.1820 + if (elseChain != null) { 1.1821 + code.resolve(elseChain); 1.1822 + if (tree.elsepart != null) { 1.1823 + genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET); 1.1824 + if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.elsepart)) { 1.1825 + code.closeAliveRanges(tree.elsepart); 1.1826 + } 1.1827 + } 1.1828 + } 1.1829 + code.resolve(thenExit); 1.1830 + code.endScopes(limit); 1.1831 + } 1.1832 + 1.1833 + public void visitExec(JCExpressionStatement tree) { 1.1834 + // Optimize x++ to ++x and x-- to --x. 1.1835 + JCExpression e = tree.expr; 1.1836 + switch (e.getTag()) { 1.1837 + case POSTINC: 1.1838 + ((JCUnary) e).setTag(PREINC); 1.1839 + break; 1.1840 + case POSTDEC: 1.1841 + ((JCUnary) e).setTag(PREDEC); 1.1842 + break; 1.1843 + } 1.1844 + genExpr(tree.expr, tree.expr.type).drop(); 1.1845 + } 1.1846 + 1.1847 + public void visitBreak(JCBreak tree) { 1.1848 + Env<GenContext> targetEnv = unwind(tree.target, env); 1.1849 + Assert.check(code.state.stacksize == 0); 1.1850 + targetEnv.info.addExit(code.branch(goto_)); 1.1851 + endFinalizerGaps(env, targetEnv); 1.1852 + } 1.1853 + 1.1854 + public void visitContinue(JCContinue tree) { 1.1855 + Env<GenContext> targetEnv = unwind(tree.target, env); 1.1856 + Assert.check(code.state.stacksize == 0); 1.1857 + targetEnv.info.addCont(code.branch(goto_)); 1.1858 + endFinalizerGaps(env, targetEnv); 1.1859 + } 1.1860 + 1.1861 + public void visitReturn(JCReturn tree) { 1.1862 + int limit = code.nextreg; 1.1863 + final Env<GenContext> targetEnv; 1.1864 + if (tree.expr != null) { 1.1865 + Item r = genExpr(tree.expr, pt).load(); 1.1866 + if (hasFinally(env.enclMethod, env)) { 1.1867 + r = makeTemp(pt); 1.1868 + r.store(); 1.1869 + } 1.1870 + targetEnv = unwind(env.enclMethod, env); 1.1871 + r.load(); 1.1872 + code.emitop0(ireturn + Code.truncate(Code.typecode(pt))); 1.1873 + } else { 1.1874 + /* If we have a statement like: 1.1875 + * 1.1876 + * return; 1.1877 + * 1.1878 + * we need to store the code.pendingStatPos value before generating 1.1879 + * the finalizer. 1.1880 + */ 1.1881 + int tmpPos = code.pendingStatPos; 1.1882 + targetEnv = unwind(env.enclMethod, env); 1.1883 + code.pendingStatPos = tmpPos; 1.1884 + code.emitop0(return_); 1.1885 + } 1.1886 + endFinalizerGaps(env, targetEnv); 1.1887 + code.endScopes(limit); 1.1888 + } 1.1889 + 1.1890 + public void visitThrow(JCThrow tree) { 1.1891 + genExpr(tree.expr, tree.expr.type).load(); 1.1892 + code.emitop0(athrow); 1.1893 + } 1.1894 + 1.1895 +/* ************************************************************************ 1.1896 + * Visitor methods for expressions 1.1897 + *************************************************************************/ 1.1898 + 1.1899 + public void visitApply(JCMethodInvocation tree) { 1.1900 + setTypeAnnotationPositions(tree.pos); 1.1901 + // Generate code for method. 1.1902 + Item m = genExpr(tree.meth, methodType); 1.1903 + // Generate code for all arguments, where the expected types are 1.1904 + // the parameters of the method's external type (that is, any implicit 1.1905 + // outer instance of a super(...) call appears as first parameter). 1.1906 + MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth); 1.1907 + genArgs(tree.args, 1.1908 + msym.externalType(types).getParameterTypes()); 1.1909 + if (!msym.isDynamic()) { 1.1910 + code.statBegin(tree.pos); 1.1911 + } 1.1912 + result = m.invoke(); 1.1913 + } 1.1914 + 1.1915 + public void visitConditional(JCConditional tree) { 1.1916 + Chain thenExit = null; 1.1917 + CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER); 1.1918 + Chain elseChain = c.jumpFalse(); 1.1919 + if (!c.isFalse()) { 1.1920 + code.resolve(c.trueJumps); 1.1921 + int startpc = genCrt ? code.curCP() : 0; 1.1922 + genExpr(tree.truepart, pt).load(); 1.1923 + code.state.forceStackTop(tree.type); 1.1924 + if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET, 1.1925 + startpc, code.curCP()); 1.1926 + thenExit = code.branch(goto_); 1.1927 + } 1.1928 + if (elseChain != null) { 1.1929 + code.resolve(elseChain); 1.1930 + int startpc = genCrt ? code.curCP() : 0; 1.1931 + genExpr(tree.falsepart, pt).load(); 1.1932 + code.state.forceStackTop(tree.type); 1.1933 + if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET, 1.1934 + startpc, code.curCP()); 1.1935 + } 1.1936 + code.resolve(thenExit); 1.1937 + result = items.makeStackItem(pt); 1.1938 + } 1.1939 + 1.1940 + private void setTypeAnnotationPositions(int treePos) { 1.1941 + MethodSymbol meth = code.meth; 1.1942 + boolean initOrClinit = code.meth.getKind() == javax.lang.model.element.ElementKind.CONSTRUCTOR 1.1943 + || code.meth.getKind() == javax.lang.model.element.ElementKind.STATIC_INIT; 1.1944 + 1.1945 + for (Attribute.TypeCompound ta : meth.getRawTypeAttributes()) { 1.1946 + if (ta.hasUnknownPosition()) 1.1947 + ta.tryFixPosition(); 1.1948 + 1.1949 + if (ta.position.matchesPos(treePos)) 1.1950 + ta.position.updatePosOffset(code.cp); 1.1951 + } 1.1952 + 1.1953 + if (!initOrClinit) 1.1954 + return; 1.1955 + 1.1956 + for (Attribute.TypeCompound ta : meth.owner.getRawTypeAttributes()) { 1.1957 + if (ta.hasUnknownPosition()) 1.1958 + ta.tryFixPosition(); 1.1959 + 1.1960 + if (ta.position.matchesPos(treePos)) 1.1961 + ta.position.updatePosOffset(code.cp); 1.1962 + } 1.1963 + 1.1964 + ClassSymbol clazz = meth.enclClass(); 1.1965 + for (Symbol s : new com.sun.tools.javac.model.FilteredMemberList(clazz.members())) { 1.1966 + if (!s.getKind().isField()) 1.1967 + continue; 1.1968 + 1.1969 + for (Attribute.TypeCompound ta : s.getRawTypeAttributes()) { 1.1970 + if (ta.hasUnknownPosition()) 1.1971 + ta.tryFixPosition(); 1.1972 + 1.1973 + if (ta.position.matchesPos(treePos)) 1.1974 + ta.position.updatePosOffset(code.cp); 1.1975 + } 1.1976 + } 1.1977 + } 1.1978 + 1.1979 + public void visitNewClass(JCNewClass tree) { 1.1980 + // Enclosing instances or anonymous classes should have been eliminated 1.1981 + // by now. 1.1982 + Assert.check(tree.encl == null && tree.def == null); 1.1983 + setTypeAnnotationPositions(tree.pos); 1.1984 + 1.1985 + code.emitop2(new_, makeRef(tree.pos(), tree.type)); 1.1986 + code.emitop0(dup); 1.1987 + 1.1988 + // Generate code for all arguments, where the expected types are 1.1989 + // the parameters of the constructor's external type (that is, 1.1990 + // any implicit outer instance appears as first parameter). 1.1991 + genArgs(tree.args, tree.constructor.externalType(types).getParameterTypes()); 1.1992 + 1.1993 + items.makeMemberItem(tree.constructor, true).invoke(); 1.1994 + result = items.makeStackItem(tree.type); 1.1995 + } 1.1996 + 1.1997 + public void visitNewArray(JCNewArray tree) { 1.1998 + setTypeAnnotationPositions(tree.pos); 1.1999 + 1.2000 + if (tree.elems != null) { 1.2001 + Type elemtype = types.elemtype(tree.type); 1.2002 + loadIntConst(tree.elems.length()); 1.2003 + Item arr = makeNewArray(tree.pos(), tree.type, 1); 1.2004 + int i = 0; 1.2005 + for (List<JCExpression> l = tree.elems; l.nonEmpty(); l = l.tail) { 1.2006 + arr.duplicate(); 1.2007 + loadIntConst(i); 1.2008 + i++; 1.2009 + genExpr(l.head, elemtype).load(); 1.2010 + items.makeIndexedItem(elemtype).store(); 1.2011 + } 1.2012 + result = arr; 1.2013 + } else { 1.2014 + for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { 1.2015 + genExpr(l.head, syms.intType).load(); 1.2016 + } 1.2017 + result = makeNewArray(tree.pos(), tree.type, tree.dims.length()); 1.2018 + } 1.2019 + } 1.2020 +//where 1.2021 + /** Generate code to create an array with given element type and number 1.2022 + * of dimensions. 1.2023 + */ 1.2024 + Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) { 1.2025 + Type elemtype = types.elemtype(type); 1.2026 + if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) { 1.2027 + log.error(pos, "limit.dimensions"); 1.2028 + nerrs++; 1.2029 + } 1.2030 + int elemcode = Code.arraycode(elemtype); 1.2031 + if (elemcode == 0 || (elemcode == 1 && ndims == 1)) { 1.2032 + code.emitAnewarray(makeRef(pos, elemtype), type); 1.2033 + } else if (elemcode == 1) { 1.2034 + code.emitMultianewarray(ndims, makeRef(pos, type), type); 1.2035 + } else { 1.2036 + code.emitNewarray(elemcode, type); 1.2037 + } 1.2038 + return items.makeStackItem(type); 1.2039 + } 1.2040 + 1.2041 + public void visitParens(JCParens tree) { 1.2042 + result = genExpr(tree.expr, tree.expr.type); 1.2043 + } 1.2044 + 1.2045 + public void visitAssign(JCAssign tree) { 1.2046 + Item l = genExpr(tree.lhs, tree.lhs.type); 1.2047 + genExpr(tree.rhs, tree.lhs.type).load(); 1.2048 + result = items.makeAssignItem(l); 1.2049 + } 1.2050 + 1.2051 + public void visitAssignop(JCAssignOp tree) { 1.2052 + OperatorSymbol operator = (OperatorSymbol) tree.operator; 1.2053 + Item l; 1.2054 + if (operator.opcode == string_add) { 1.2055 + // Generate code to make a string buffer 1.2056 + makeStringBuffer(tree.pos()); 1.2057 + 1.2058 + // Generate code for first string, possibly save one 1.2059 + // copy under buffer 1.2060 + l = genExpr(tree.lhs, tree.lhs.type); 1.2061 + if (l.width() > 0) { 1.2062 + code.emitop0(dup_x1 + 3 * (l.width() - 1)); 1.2063 + } 1.2064 + 1.2065 + // Load first string and append to buffer. 1.2066 + l.load(); 1.2067 + appendString(tree.lhs); 1.2068 + 1.2069 + // Append all other strings to buffer. 1.2070 + appendStrings(tree.rhs); 1.2071 + 1.2072 + // Convert buffer to string. 1.2073 + bufferToString(tree.pos()); 1.2074 + } else { 1.2075 + // Generate code for first expression 1.2076 + l = genExpr(tree.lhs, tree.lhs.type); 1.2077 + 1.2078 + // If we have an increment of -32768 to +32767 of a local 1.2079 + // int variable we can use an incr instruction instead of 1.2080 + // proceeding further. 1.2081 + if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) && 1.2082 + l instanceof LocalItem && 1.2083 + tree.lhs.type.getTag().isSubRangeOf(INT) && 1.2084 + tree.rhs.type.getTag().isSubRangeOf(INT) && 1.2085 + tree.rhs.type.constValue() != null) { 1.2086 + int ival = ((Number) tree.rhs.type.constValue()).intValue(); 1.2087 + if (tree.hasTag(MINUS_ASG)) ival = -ival; 1.2088 + ((LocalItem)l).incr(ival); 1.2089 + result = l; 1.2090 + return; 1.2091 + } 1.2092 + // Otherwise, duplicate expression, load one copy 1.2093 + // and complete binary operation. 1.2094 + l.duplicate(); 1.2095 + l.coerce(operator.type.getParameterTypes().head).load(); 1.2096 + completeBinop(tree.lhs, tree.rhs, operator).coerce(tree.lhs.type); 1.2097 + } 1.2098 + result = items.makeAssignItem(l); 1.2099 + } 1.2100 + 1.2101 + public void visitUnary(JCUnary tree) { 1.2102 + OperatorSymbol operator = (OperatorSymbol)tree.operator; 1.2103 + if (tree.hasTag(NOT)) { 1.2104 + CondItem od = genCond(tree.arg, false); 1.2105 + result = od.negate(); 1.2106 + } else { 1.2107 + Item od = genExpr(tree.arg, operator.type.getParameterTypes().head); 1.2108 + switch (tree.getTag()) { 1.2109 + case POS: 1.2110 + result = od.load(); 1.2111 + break; 1.2112 + case NEG: 1.2113 + result = od.load(); 1.2114 + code.emitop0(operator.opcode); 1.2115 + break; 1.2116 + case COMPL: 1.2117 + result = od.load(); 1.2118 + emitMinusOne(od.typecode); 1.2119 + code.emitop0(operator.opcode); 1.2120 + break; 1.2121 + case PREINC: case PREDEC: 1.2122 + od.duplicate(); 1.2123 + if (od instanceof LocalItem && 1.2124 + (operator.opcode == iadd || operator.opcode == isub)) { 1.2125 + ((LocalItem)od).incr(tree.hasTag(PREINC) ? 1 : -1); 1.2126 + result = od; 1.2127 + } else { 1.2128 + od.load(); 1.2129 + code.emitop0(one(od.typecode)); 1.2130 + code.emitop0(operator.opcode); 1.2131 + // Perform narrowing primitive conversion if byte, 1.2132 + // char, or short. Fix for 4304655. 1.2133 + if (od.typecode != INTcode && 1.2134 + Code.truncate(od.typecode) == INTcode) 1.2135 + code.emitop0(int2byte + od.typecode - BYTEcode); 1.2136 + result = items.makeAssignItem(od); 1.2137 + } 1.2138 + break; 1.2139 + case POSTINC: case POSTDEC: 1.2140 + od.duplicate(); 1.2141 + if (od instanceof LocalItem && 1.2142 + (operator.opcode == iadd || operator.opcode == isub)) { 1.2143 + Item res = od.load(); 1.2144 + ((LocalItem)od).incr(tree.hasTag(POSTINC) ? 1 : -1); 1.2145 + result = res; 1.2146 + } else { 1.2147 + Item res = od.load(); 1.2148 + od.stash(od.typecode); 1.2149 + code.emitop0(one(od.typecode)); 1.2150 + code.emitop0(operator.opcode); 1.2151 + // Perform narrowing primitive conversion if byte, 1.2152 + // char, or short. Fix for 4304655. 1.2153 + if (od.typecode != INTcode && 1.2154 + Code.truncate(od.typecode) == INTcode) 1.2155 + code.emitop0(int2byte + od.typecode - BYTEcode); 1.2156 + od.store(); 1.2157 + result = res; 1.2158 + } 1.2159 + break; 1.2160 + case NULLCHK: 1.2161 + result = od.load(); 1.2162 + code.emitop0(dup); 1.2163 + genNullCheck(tree.pos()); 1.2164 + break; 1.2165 + default: 1.2166 + Assert.error(); 1.2167 + } 1.2168 + } 1.2169 + } 1.2170 + 1.2171 + /** Generate a null check from the object value at stack top. */ 1.2172 + private void genNullCheck(DiagnosticPosition pos) { 1.2173 + callMethod(pos, syms.objectType, names.getClass, 1.2174 + List.<Type>nil(), false); 1.2175 + code.emitop0(pop); 1.2176 + } 1.2177 + 1.2178 + public void visitBinary(JCBinary tree) { 1.2179 + OperatorSymbol operator = (OperatorSymbol)tree.operator; 1.2180 + if (operator.opcode == string_add) { 1.2181 + // Create a string buffer. 1.2182 + makeStringBuffer(tree.pos()); 1.2183 + // Append all strings to buffer. 1.2184 + appendStrings(tree); 1.2185 + // Convert buffer to string. 1.2186 + bufferToString(tree.pos()); 1.2187 + result = items.makeStackItem(syms.stringType); 1.2188 + } else if (tree.hasTag(AND)) { 1.2189 + CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); 1.2190 + if (!lcond.isFalse()) { 1.2191 + Chain falseJumps = lcond.jumpFalse(); 1.2192 + code.resolve(lcond.trueJumps); 1.2193 + CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET); 1.2194 + result = items. 1.2195 + makeCondItem(rcond.opcode, 1.2196 + rcond.trueJumps, 1.2197 + Code.mergeChains(falseJumps, 1.2198 + rcond.falseJumps)); 1.2199 + } else { 1.2200 + result = lcond; 1.2201 + } 1.2202 + } else if (tree.hasTag(OR)) { 1.2203 + CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); 1.2204 + if (!lcond.isTrue()) { 1.2205 + Chain trueJumps = lcond.jumpTrue(); 1.2206 + code.resolve(lcond.falseJumps); 1.2207 + CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET); 1.2208 + result = items. 1.2209 + makeCondItem(rcond.opcode, 1.2210 + Code.mergeChains(trueJumps, rcond.trueJumps), 1.2211 + rcond.falseJumps); 1.2212 + } else { 1.2213 + result = lcond; 1.2214 + } 1.2215 + } else { 1.2216 + Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head); 1.2217 + od.load(); 1.2218 + result = completeBinop(tree.lhs, tree.rhs, operator); 1.2219 + } 1.2220 + } 1.2221 +//where 1.2222 + /** Make a new string buffer. 1.2223 + */ 1.2224 + void makeStringBuffer(DiagnosticPosition pos) { 1.2225 + code.emitop2(new_, makeRef(pos, stringBufferType)); 1.2226 + code.emitop0(dup); 1.2227 + callMethod( 1.2228 + pos, stringBufferType, names.init, List.<Type>nil(), false); 1.2229 + } 1.2230 + 1.2231 + /** Append value (on tos) to string buffer (on tos - 1). 1.2232 + */ 1.2233 + void appendString(JCTree tree) { 1.2234 + Type t = tree.type.baseType(); 1.2235 + if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) { 1.2236 + t = syms.objectType; 1.2237 + } 1.2238 + items.makeMemberItem(getStringBufferAppend(tree, t), false).invoke(); 1.2239 + } 1.2240 + Symbol getStringBufferAppend(JCTree tree, Type t) { 1.2241 + Assert.checkNull(t.constValue()); 1.2242 + Symbol method = stringBufferAppend.get(t); 1.2243 + if (method == null) { 1.2244 + method = rs.resolveInternalMethod(tree.pos(), 1.2245 + attrEnv, 1.2246 + stringBufferType, 1.2247 + names.append, 1.2248 + List.of(t), 1.2249 + null); 1.2250 + stringBufferAppend.put(t, method); 1.2251 + } 1.2252 + return method; 1.2253 + } 1.2254 + 1.2255 + /** Add all strings in tree to string buffer. 1.2256 + */ 1.2257 + void appendStrings(JCTree tree) { 1.2258 + tree = TreeInfo.skipParens(tree); 1.2259 + if (tree.hasTag(PLUS) && tree.type.constValue() == null) { 1.2260 + JCBinary op = (JCBinary) tree; 1.2261 + if (op.operator.kind == MTH && 1.2262 + ((OperatorSymbol) op.operator).opcode == string_add) { 1.2263 + appendStrings(op.lhs); 1.2264 + appendStrings(op.rhs); 1.2265 + return; 1.2266 + } 1.2267 + } 1.2268 + genExpr(tree, tree.type).load(); 1.2269 + appendString(tree); 1.2270 + } 1.2271 + 1.2272 + /** Convert string buffer on tos to string. 1.2273 + */ 1.2274 + void bufferToString(DiagnosticPosition pos) { 1.2275 + callMethod( 1.2276 + pos, 1.2277 + stringBufferType, 1.2278 + names.toString, 1.2279 + List.<Type>nil(), 1.2280 + false); 1.2281 + } 1.2282 + 1.2283 + /** Complete generating code for operation, with left operand 1.2284 + * already on stack. 1.2285 + * @param lhs The tree representing the left operand. 1.2286 + * @param rhs The tree representing the right operand. 1.2287 + * @param operator The operator symbol. 1.2288 + */ 1.2289 + Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) { 1.2290 + MethodType optype = (MethodType)operator.type; 1.2291 + int opcode = operator.opcode; 1.2292 + if (opcode >= if_icmpeq && opcode <= if_icmple && 1.2293 + rhs.type.constValue() instanceof Number && 1.2294 + ((Number) rhs.type.constValue()).intValue() == 0) { 1.2295 + opcode = opcode + (ifeq - if_icmpeq); 1.2296 + } else if (opcode >= if_acmpeq && opcode <= if_acmpne && 1.2297 + TreeInfo.isNull(rhs)) { 1.2298 + opcode = opcode + (if_acmp_null - if_acmpeq); 1.2299 + } else { 1.2300 + // The expected type of the right operand is 1.2301 + // the second parameter type of the operator, except for 1.2302 + // shifts with long shiftcount, where we convert the opcode 1.2303 + // to a short shift and the expected type to int. 1.2304 + Type rtype = operator.erasure(types).getParameterTypes().tail.head; 1.2305 + if (opcode >= ishll && opcode <= lushrl) { 1.2306 + opcode = opcode + (ishl - ishll); 1.2307 + rtype = syms.intType; 1.2308 + } 1.2309 + // Generate code for right operand and load. 1.2310 + genExpr(rhs, rtype).load(); 1.2311 + // If there are two consecutive opcode instructions, 1.2312 + // emit the first now. 1.2313 + if (opcode >= (1 << preShift)) { 1.2314 + code.emitop0(opcode >> preShift); 1.2315 + opcode = opcode & 0xFF; 1.2316 + } 1.2317 + } 1.2318 + if (opcode >= ifeq && opcode <= if_acmpne || 1.2319 + opcode == if_acmp_null || opcode == if_acmp_nonnull) { 1.2320 + return items.makeCondItem(opcode); 1.2321 + } else { 1.2322 + code.emitop0(opcode); 1.2323 + return items.makeStackItem(optype.restype); 1.2324 + } 1.2325 + } 1.2326 + 1.2327 + public void visitTypeCast(JCTypeCast tree) { 1.2328 + setTypeAnnotationPositions(tree.pos); 1.2329 + result = genExpr(tree.expr, tree.clazz.type).load(); 1.2330 + // Additional code is only needed if we cast to a reference type 1.2331 + // which is not statically a supertype of the expression's type. 1.2332 + // For basic types, the coerce(...) in genExpr(...) will do 1.2333 + // the conversion. 1.2334 + if (!tree.clazz.type.isPrimitive() && 1.2335 + types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) { 1.2336 + code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type)); 1.2337 + } 1.2338 + } 1.2339 + 1.2340 + public void visitWildcard(JCWildcard tree) { 1.2341 + throw new AssertionError(this.getClass().getName()); 1.2342 + } 1.2343 + 1.2344 + public void visitTypeTest(JCInstanceOf tree) { 1.2345 + setTypeAnnotationPositions(tree.pos); 1.2346 + genExpr(tree.expr, tree.expr.type).load(); 1.2347 + code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type)); 1.2348 + result = items.makeStackItem(syms.booleanType); 1.2349 + } 1.2350 + 1.2351 + public void visitIndexed(JCArrayAccess tree) { 1.2352 + genExpr(tree.indexed, tree.indexed.type).load(); 1.2353 + genExpr(tree.index, syms.intType).load(); 1.2354 + result = items.makeIndexedItem(tree.type); 1.2355 + } 1.2356 + 1.2357 + public void visitIdent(JCIdent tree) { 1.2358 + Symbol sym = tree.sym; 1.2359 + if (tree.name == names._this || tree.name == names._super) { 1.2360 + Item res = tree.name == names._this 1.2361 + ? items.makeThisItem() 1.2362 + : items.makeSuperItem(); 1.2363 + if (sym.kind == MTH) { 1.2364 + // Generate code to address the constructor. 1.2365 + res.load(); 1.2366 + res = items.makeMemberItem(sym, true); 1.2367 + } 1.2368 + result = res; 1.2369 + } else if (sym.kind == VAR && sym.owner.kind == MTH) { 1.2370 + result = items.makeLocalItem((VarSymbol)sym); 1.2371 + } else if (isInvokeDynamic(sym)) { 1.2372 + result = items.makeDynamicItem(sym); 1.2373 + } else if ((sym.flags() & STATIC) != 0) { 1.2374 + if (!isAccessSuper(env.enclMethod)) 1.2375 + sym = binaryQualifier(sym, env.enclClass.type); 1.2376 + result = items.makeStaticItem(sym); 1.2377 + } else { 1.2378 + items.makeThisItem().load(); 1.2379 + sym = binaryQualifier(sym, env.enclClass.type); 1.2380 + result = items.makeMemberItem(sym, (sym.flags() & PRIVATE) != 0); 1.2381 + } 1.2382 + } 1.2383 + 1.2384 + public void visitSelect(JCFieldAccess tree) { 1.2385 + Symbol sym = tree.sym; 1.2386 + 1.2387 + if (tree.name == names._class) { 1.2388 + Assert.check(target.hasClassLiterals()); 1.2389 + code.emitLdc(makeRef(tree.pos(), tree.selected.type)); 1.2390 + result = items.makeStackItem(pt); 1.2391 + return; 1.2392 + } 1.2393 + 1.2394 + Symbol ssym = TreeInfo.symbol(tree.selected); 1.2395 + 1.2396 + // Are we selecting via super? 1.2397 + boolean selectSuper = 1.2398 + ssym != null && (ssym.kind == TYP || ssym.name == names._super); 1.2399 + 1.2400 + // Are we accessing a member of the superclass in an access method 1.2401 + // resulting from a qualified super? 1.2402 + boolean accessSuper = isAccessSuper(env.enclMethod); 1.2403 + 1.2404 + Item base = (selectSuper) 1.2405 + ? items.makeSuperItem() 1.2406 + : genExpr(tree.selected, tree.selected.type); 1.2407 + 1.2408 + if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) { 1.2409 + // We are seeing a variable that is constant but its selecting 1.2410 + // expression is not. 1.2411 + if ((sym.flags() & STATIC) != 0) { 1.2412 + if (!selectSuper && (ssym == null || ssym.kind != TYP)) 1.2413 + base = base.load(); 1.2414 + base.drop(); 1.2415 + } else { 1.2416 + base.load(); 1.2417 + genNullCheck(tree.selected.pos()); 1.2418 + } 1.2419 + result = items. 1.2420 + makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue()); 1.2421 + } else { 1.2422 + if (isInvokeDynamic(sym)) { 1.2423 + result = items.makeDynamicItem(sym); 1.2424 + return; 1.2425 + } else { 1.2426 + sym = binaryQualifier(sym, tree.selected.type); 1.2427 + } 1.2428 + if ((sym.flags() & STATIC) != 0) { 1.2429 + if (!selectSuper && (ssym == null || ssym.kind != TYP)) 1.2430 + base = base.load(); 1.2431 + base.drop(); 1.2432 + result = items.makeStaticItem(sym); 1.2433 + } else { 1.2434 + base.load(); 1.2435 + if (sym == syms.lengthVar) { 1.2436 + code.emitop0(arraylength); 1.2437 + result = items.makeStackItem(syms.intType); 1.2438 + } else { 1.2439 + result = items. 1.2440 + makeMemberItem(sym, 1.2441 + (sym.flags() & PRIVATE) != 0 || 1.2442 + selectSuper || accessSuper); 1.2443 + } 1.2444 + } 1.2445 + } 1.2446 + } 1.2447 + 1.2448 + public boolean isInvokeDynamic(Symbol sym) { 1.2449 + return sym.kind == MTH && ((MethodSymbol)sym).isDynamic(); 1.2450 + } 1.2451 + 1.2452 + public void visitLiteral(JCLiteral tree) { 1.2453 + if (tree.type.hasTag(BOT)) { 1.2454 + code.emitop0(aconst_null); 1.2455 + if (types.dimensions(pt) > 1) { 1.2456 + code.emitop2(checkcast, makeRef(tree.pos(), pt)); 1.2457 + result = items.makeStackItem(pt); 1.2458 + } else { 1.2459 + result = items.makeStackItem(tree.type); 1.2460 + } 1.2461 + } 1.2462 + else 1.2463 + result = items.makeImmediateItem(tree.type, tree.value); 1.2464 + } 1.2465 + 1.2466 + public void visitLetExpr(LetExpr tree) { 1.2467 + int limit = code.nextreg; 1.2468 + genStats(tree.defs, env); 1.2469 + result = genExpr(tree.expr, tree.expr.type).load(); 1.2470 + code.endScopes(limit); 1.2471 + } 1.2472 + 1.2473 + private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) { 1.2474 + List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol); 1.2475 + if (prunedInfo != null) { 1.2476 + for (JCTree prunedTree: prunedInfo) { 1.2477 + prunedTree.accept(classReferenceVisitor); 1.2478 + } 1.2479 + } 1.2480 + } 1.2481 + 1.2482 +/* ************************************************************************ 1.2483 + * main method 1.2484 + *************************************************************************/ 1.2485 + 1.2486 + /** Generate code for a class definition. 1.2487 + * @param env The attribution environment that belongs to the 1.2488 + * outermost class containing this class definition. 1.2489 + * We need this for resolving some additional symbols. 1.2490 + * @param cdef The tree representing the class definition. 1.2491 + * @return True if code is generated with no errors. 1.2492 + */ 1.2493 + public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) { 1.2494 + try { 1.2495 + attrEnv = env; 1.2496 + ClassSymbol c = cdef.sym; 1.2497 + this.toplevel = env.toplevel; 1.2498 + this.endPosTable = toplevel.endPositions; 1.2499 + // If this is a class definition requiring Miranda methods, 1.2500 + // add them. 1.2501 + if (generateIproxies && 1.2502 + (c.flags() & (INTERFACE|ABSTRACT)) == ABSTRACT 1.2503 + && !allowGenerics // no Miranda methods available with generics 1.2504 + ) 1.2505 + implementInterfaceMethods(c); 1.2506 + cdef.defs = normalizeDefs(cdef.defs, c); 1.2507 + c.pool = pool; 1.2508 + pool.reset(); 1.2509 + generateReferencesToPrunedTree(c, pool); 1.2510 + Env<GenContext> localEnv = 1.2511 + new Env<GenContext>(cdef, new GenContext()); 1.2512 + localEnv.toplevel = env.toplevel; 1.2513 + localEnv.enclClass = cdef; 1.2514 + 1.2515 + /* We must not analyze synthetic methods 1.2516 + */ 1.2517 + if (varDebugInfo && (cdef.sym.flags() & SYNTHETIC) == 0) { 1.2518 + try { 1.2519 + LVTAssignAnalyzer lvtAssignAnalyzer = LVTAssignAnalyzer.make( 1.2520 + lvtRanges, syms, names); 1.2521 + lvtAssignAnalyzer.analyzeTree(localEnv); 1.2522 + } catch (Throwable e) { 1.2523 + throw e; 1.2524 + } 1.2525 + } 1.2526 + 1.2527 + for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) { 1.2528 + genDef(l.head, localEnv); 1.2529 + } 1.2530 + if (pool.numEntries() > Pool.MAX_ENTRIES) { 1.2531 + log.error(cdef.pos(), "limit.pool"); 1.2532 + nerrs++; 1.2533 + } 1.2534 + if (nerrs != 0) { 1.2535 + // if errors, discard code 1.2536 + for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) { 1.2537 + if (l.head.hasTag(METHODDEF)) 1.2538 + ((JCMethodDecl) l.head).sym.code = null; 1.2539 + } 1.2540 + } 1.2541 + cdef.defs = List.nil(); // discard trees 1.2542 + return nerrs == 0; 1.2543 + } finally { 1.2544 + // note: this method does NOT support recursion. 1.2545 + attrEnv = null; 1.2546 + this.env = null; 1.2547 + toplevel = null; 1.2548 + endPosTable = null; 1.2549 + nerrs = 0; 1.2550 + } 1.2551 + } 1.2552 + 1.2553 +/* ************************************************************************ 1.2554 + * Auxiliary classes 1.2555 + *************************************************************************/ 1.2556 + 1.2557 + /** An abstract class for finalizer generation. 1.2558 + */ 1.2559 + abstract class GenFinalizer { 1.2560 + /** Generate code to clean up when unwinding. */ 1.2561 + abstract void gen(); 1.2562 + 1.2563 + /** Generate code to clean up at last. */ 1.2564 + abstract void genLast(); 1.2565 + 1.2566 + /** Does this finalizer have some nontrivial cleanup to perform? */ 1.2567 + boolean hasFinalizer() { return true; } 1.2568 + } 1.2569 + 1.2570 + /** code generation contexts, 1.2571 + * to be used as type parameter for environments. 1.2572 + */ 1.2573 + static class GenContext { 1.2574 + 1.2575 + /** A chain for all unresolved jumps that exit the current environment. 1.2576 + */ 1.2577 + Chain exit = null; 1.2578 + 1.2579 + /** A chain for all unresolved jumps that continue in the 1.2580 + * current environment. 1.2581 + */ 1.2582 + Chain cont = null; 1.2583 + 1.2584 + /** A closure that generates the finalizer of the current environment. 1.2585 + * Only set for Synchronized and Try contexts. 1.2586 + */ 1.2587 + GenFinalizer finalize = null; 1.2588 + 1.2589 + /** Is this a switch statement? If so, allocate registers 1.2590 + * even when the variable declaration is unreachable. 1.2591 + */ 1.2592 + boolean isSwitch = false; 1.2593 + 1.2594 + /** A list buffer containing all gaps in the finalizer range, 1.2595 + * where a catch all exception should not apply. 1.2596 + */ 1.2597 + ListBuffer<Integer> gaps = null; 1.2598 + 1.2599 + /** Add given chain to exit chain. 1.2600 + */ 1.2601 + void addExit(Chain c) { 1.2602 + exit = Code.mergeChains(c, exit); 1.2603 + } 1.2604 + 1.2605 + /** Add given chain to cont chain. 1.2606 + */ 1.2607 + void addCont(Chain c) { 1.2608 + cont = Code.mergeChains(c, cont); 1.2609 + } 1.2610 + } 1.2611 + 1.2612 + static class LVTAssignAnalyzer 1.2613 + extends Flow.AbstractAssignAnalyzer<LVTAssignAnalyzer.LVTAssignPendingExit> { 1.2614 + 1.2615 + final LVTBits lvtInits; 1.2616 + final LVTRanges lvtRanges; 1.2617 + 1.2618 + /* This class is anchored to a context dependent tree. The tree can 1.2619 + * vary inside the same instruction for example in the switch instruction 1.2620 + * the same FlowBits instance can be anchored to the whole tree, or 1.2621 + * to a given case. The aim is to always anchor the bits to the tree 1.2622 + * capable of closing a DA range. 1.2623 + */ 1.2624 + static class LVTBits extends Bits { 1.2625 + 1.2626 + enum BitsOpKind { 1.2627 + INIT, 1.2628 + CLEAR, 1.2629 + INCL_BIT, 1.2630 + EXCL_BIT, 1.2631 + ASSIGN, 1.2632 + AND_SET, 1.2633 + OR_SET, 1.2634 + DIFF_SET, 1.2635 + XOR_SET, 1.2636 + INCL_RANGE, 1.2637 + EXCL_RANGE, 1.2638 + } 1.2639 + 1.2640 + JCTree currentTree; 1.2641 + LVTAssignAnalyzer analyzer; 1.2642 + private int[] oldBits = null; 1.2643 + BitsState stateBeforeOp; 1.2644 + 1.2645 + LVTBits() { 1.2646 + super(false); 1.2647 + } 1.2648 + 1.2649 + LVTBits(int[] bits, BitsState initState) { 1.2650 + super(bits, initState); 1.2651 + } 1.2652 + 1.2653 + @Override 1.2654 + public void clear() { 1.2655 + generalOp(null, -1, BitsOpKind.CLEAR); 1.2656 + } 1.2657 + 1.2658 + @Override 1.2659 + protected void internalReset() { 1.2660 + super.internalReset(); 1.2661 + oldBits = null; 1.2662 + } 1.2663 + 1.2664 + @Override 1.2665 + public Bits assign(Bits someBits) { 1.2666 + // bits can be null 1.2667 + oldBits = bits; 1.2668 + stateBeforeOp = currentState; 1.2669 + super.assign(someBits); 1.2670 + changed(); 1.2671 + return this; 1.2672 + } 1.2673 + 1.2674 + @Override 1.2675 + public void excludeFrom(int start) { 1.2676 + generalOp(null, start, BitsOpKind.EXCL_RANGE); 1.2677 + } 1.2678 + 1.2679 + @Override 1.2680 + public void excl(int x) { 1.2681 + Assert.check(x >= 0); 1.2682 + generalOp(null, x, BitsOpKind.EXCL_BIT); 1.2683 + } 1.2684 + 1.2685 + @Override 1.2686 + public Bits andSet(Bits xs) { 1.2687 + return generalOp(xs, -1, BitsOpKind.AND_SET); 1.2688 + } 1.2689 + 1.2690 + @Override 1.2691 + public Bits orSet(Bits xs) { 1.2692 + return generalOp(xs, -1, BitsOpKind.OR_SET); 1.2693 + } 1.2694 + 1.2695 + @Override 1.2696 + public Bits diffSet(Bits xs) { 1.2697 + return generalOp(xs, -1, BitsOpKind.DIFF_SET); 1.2698 + } 1.2699 + 1.2700 + @Override 1.2701 + public Bits xorSet(Bits xs) { 1.2702 + return generalOp(xs, -1, BitsOpKind.XOR_SET); 1.2703 + } 1.2704 + 1.2705 + private Bits generalOp(Bits xs, int i, BitsOpKind opKind) { 1.2706 + Assert.check(currentState != BitsState.UNKNOWN); 1.2707 + oldBits = dupBits(); 1.2708 + stateBeforeOp = currentState; 1.2709 + switch (opKind) { 1.2710 + case AND_SET: 1.2711 + super.andSet(xs); 1.2712 + break; 1.2713 + case OR_SET: 1.2714 + super.orSet(xs); 1.2715 + break; 1.2716 + case XOR_SET: 1.2717 + super.xorSet(xs); 1.2718 + break; 1.2719 + case DIFF_SET: 1.2720 + super.diffSet(xs); 1.2721 + break; 1.2722 + case CLEAR: 1.2723 + super.clear(); 1.2724 + break; 1.2725 + case EXCL_BIT: 1.2726 + super.excl(i); 1.2727 + break; 1.2728 + case EXCL_RANGE: 1.2729 + super.excludeFrom(i); 1.2730 + break; 1.2731 + } 1.2732 + changed(); 1.2733 + return this; 1.2734 + } 1.2735 + 1.2736 + /* The tree we need to anchor the bits instance to. 1.2737 + */ 1.2738 + LVTBits at(JCTree tree) { 1.2739 + this.currentTree = tree; 1.2740 + return this; 1.2741 + } 1.2742 + 1.2743 + /* If the instance should be changed but the tree is not a closing 1.2744 + * tree then a reset is needed or the former tree can mistakingly be 1.2745 + * used. 1.2746 + */ 1.2747 + LVTBits resetTree() { 1.2748 + this.currentTree = null; 1.2749 + return this; 1.2750 + } 1.2751 + 1.2752 + /** This method will be called after any operation that causes a change to 1.2753 + * the bits. Subclasses can thus override it in order to extract information 1.2754 + * from the changes produced to the bits by the given operation. 1.2755 + */ 1.2756 + public void changed() { 1.2757 + if (currentTree != null && 1.2758 + stateBeforeOp != BitsState.UNKNOWN && 1.2759 + trackTree(currentTree)) { 1.2760 + List<VarSymbol> locals = 1.2761 + analyzer.lvtRanges 1.2762 + .getVars(analyzer.currentMethod, currentTree); 1.2763 + locals = locals != null ? 1.2764 + locals : List.<VarSymbol>nil(); 1.2765 + for (JCVariableDecl vardecl : analyzer.vardecls) { 1.2766 + //once the first is null, the rest will be so. 1.2767 + if (vardecl == null) { 1.2768 + break; 1.2769 + } 1.2770 + if (trackVar(vardecl.sym) && bitChanged(vardecl.sym.adr)) { 1.2771 + locals = locals.prepend(vardecl.sym); 1.2772 + } 1.2773 + } 1.2774 + if (!locals.isEmpty()) { 1.2775 + analyzer.lvtRanges.setEntry(analyzer.currentMethod, 1.2776 + currentTree, locals); 1.2777 + } 1.2778 + } 1.2779 + } 1.2780 + 1.2781 + boolean bitChanged(int x) { 1.2782 + boolean isMemberOfBits = isMember(x); 1.2783 + int[] tmp = bits; 1.2784 + bits = oldBits; 1.2785 + boolean isMemberOfOldBits = isMember(x); 1.2786 + bits = tmp; 1.2787 + return (!isMemberOfBits && isMemberOfOldBits); 1.2788 + } 1.2789 + 1.2790 + boolean trackVar(VarSymbol var) { 1.2791 + return (var.owner.kind == MTH && 1.2792 + (var.flags() & (PARAMETER | HASINIT)) == 0 && 1.2793 + analyzer.trackable(var)); 1.2794 + } 1.2795 + 1.2796 + boolean trackTree(JCTree tree) { 1.2797 + switch (tree.getTag()) { 1.2798 + // of course a method closes the alive range of a local variable. 1.2799 + case METHODDEF: 1.2800 + // for while loops we want only the body 1.2801 + case WHILELOOP: 1.2802 + return false; 1.2803 + } 1.2804 + return true; 1.2805 + } 1.2806 + 1.2807 + } 1.2808 + 1.2809 + public class LVTAssignPendingExit extends Flow.AssignAnalyzer.AssignPendingExit { 1.2810 + 1.2811 + LVTAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { 1.2812 + super(tree, inits, uninits); 1.2813 + } 1.2814 + 1.2815 + @Override 1.2816 + public void resolveJump(JCTree tree) { 1.2817 + lvtInits.at(tree); 1.2818 + super.resolveJump(tree); 1.2819 + } 1.2820 + } 1.2821 + 1.2822 + private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) { 1.2823 + super(new LVTBits(), syms, names, false); 1.2824 + lvtInits = (LVTBits)inits; 1.2825 + this.lvtRanges = lvtRanges; 1.2826 + } 1.2827 + 1.2828 + public static LVTAssignAnalyzer make(LVTRanges lvtRanges, Symtab syms, Names names) { 1.2829 + LVTAssignAnalyzer result = new LVTAssignAnalyzer(lvtRanges, syms, names); 1.2830 + result.lvtInits.analyzer = result; 1.2831 + return result; 1.2832 + } 1.2833 + 1.2834 + @Override 1.2835 + protected void markDead(JCTree tree) { 1.2836 + lvtInits.at(tree).inclRange(returnadr, nextadr); 1.2837 + super.markDead(tree); 1.2838 + } 1.2839 + 1.2840 + @Override 1.2841 + protected void merge(JCTree tree) { 1.2842 + lvtInits.at(tree); 1.2843 + super.merge(tree); 1.2844 + } 1.2845 + 1.2846 + boolean isSyntheticOrMandated(Symbol sym) { 1.2847 + return (sym.flags() & (SYNTHETIC | MANDATED)) != 0; 1.2848 + } 1.2849 + 1.2850 + @Override 1.2851 + protected boolean trackable(VarSymbol sym) { 1.2852 + if (isSyntheticOrMandated(sym)) { 1.2853 + //fast check to avoid tracking synthetic or mandated variables 1.2854 + return false; 1.2855 + } 1.2856 + return super.trackable(sym); 1.2857 + } 1.2858 + 1.2859 + @Override 1.2860 + protected void initParam(JCVariableDecl def) { 1.2861 + if (!isSyntheticOrMandated(def.sym)) { 1.2862 + super.initParam(def); 1.2863 + } 1.2864 + } 1.2865 + 1.2866 + @Override 1.2867 + protected void assignToInits(JCTree tree, Bits bits) { 1.2868 + lvtInits.at(tree); 1.2869 + lvtInits.assign(bits); 1.2870 + } 1.2871 + 1.2872 + @Override 1.2873 + protected void andSetInits(JCTree tree, Bits bits) { 1.2874 + lvtInits.at(tree); 1.2875 + lvtInits.andSet(bits); 1.2876 + } 1.2877 + 1.2878 + @Override 1.2879 + protected void orSetInits(JCTree tree, Bits bits) { 1.2880 + lvtInits.at(tree); 1.2881 + lvtInits.orSet(bits); 1.2882 + } 1.2883 + 1.2884 + @Override 1.2885 + protected void exclVarFromInits(JCTree tree, int adr) { 1.2886 + lvtInits.at(tree); 1.2887 + lvtInits.excl(adr); 1.2888 + } 1.2889 + 1.2890 + @Override 1.2891 + protected LVTAssignPendingExit createNewPendingExit(JCTree tree, Bits inits, Bits uninits) { 1.2892 + return new LVTAssignPendingExit(tree, inits, uninits); 1.2893 + } 1.2894 + 1.2895 + MethodSymbol currentMethod; 1.2896 + 1.2897 + @Override 1.2898 + public void visitMethodDef(JCMethodDecl tree) { 1.2899 + if ((tree.sym.flags() & (SYNTHETIC | GENERATEDCONSTR)) != 0 1.2900 + && (tree.sym.flags() & LAMBDA_METHOD) == 0) { 1.2901 + return; 1.2902 + } 1.2903 + if (tree.name.equals(names.clinit)) { 1.2904 + return; 1.2905 + } 1.2906 + boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0; 1.2907 + if (enumClass && 1.2908 + (tree.name.equals(names.valueOf) || 1.2909 + tree.name.equals(names.values) || 1.2910 + tree.name.equals(names.init))) { 1.2911 + return; 1.2912 + } 1.2913 + currentMethod = tree.sym; 1.2914 + 1.2915 + super.visitMethodDef(tree); 1.2916 + } 1.2917 + 1.2918 + } 1.2919 + 1.2920 +}