1 /* 2 * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.tree; 27 28 import sun.tools.java.*; 29 import sun.tools.asm.Assembler; 30 31 /** 32 * WARNING: The contents of this source file are not part of any 33 * supported API. Code that depends on them does so at its own risk: 34 * they are subject to change or removal without notice. 35 */ 36 public 37 class Context implements Constants { 38 Context prev; 39 Node node; 40 int varNumber; 41 LocalMember locals; 42 LocalMember classes; 43 MemberDefinition field; 44 int scopeNumber; 45 int frameNumber; 46 47 /** 48 * Create the initial context for a method 49 * The incoming context is inherited from 50 */ Context(Context ctx, MemberDefinition field)51 public Context(Context ctx, MemberDefinition field) { 52 this.field = field; 53 if (ctx == null) { 54 this.frameNumber = 1; 55 this.scopeNumber = 2; 56 this.varNumber = 0; 57 } else { 58 this.prev = ctx; 59 this.locals = ctx.locals; 60 this.classes = ctx.classes; 61 if (field != null && 62 (field.isVariable() || field.isInitializer())) { 63 // Variables and initializers are inlined into a constructor. 64 // Model this by inheriting the frame number of the parent, 65 // which will contain a "this" parameter. 66 this.frameNumber = ctx.frameNumber; 67 this.scopeNumber = ctx.scopeNumber + 1; 68 } else { 69 this.frameNumber = ctx.scopeNumber + 1; 70 this.scopeNumber = this.frameNumber + 1; 71 } 72 this.varNumber = ctx.varNumber; 73 } 74 } 75 76 /** 77 * Create a new context, for initializing a class. 78 */ Context(Context ctx, ClassDefinition c)79 public Context(Context ctx, ClassDefinition c) { 80 this(ctx, (MemberDefinition)null); 81 } 82 83 /** 84 * Create a new nested context, for a block statement 85 */ Context(Context ctx, Node node)86 Context(Context ctx, Node node) { 87 if (ctx == null) { 88 this.frameNumber = 1; 89 this.scopeNumber = 2; 90 this.varNumber = 0; 91 } else { 92 this.prev = ctx; 93 this.locals = ctx.locals; 94 // Inherit local classes from surrounding block, 95 // just as for local variables. Fixes 4074421. 96 this.classes = ctx.classes; 97 this.varNumber = ctx.varNumber; 98 this.field = ctx.field; 99 this.frameNumber = ctx.frameNumber; 100 this.scopeNumber = ctx.scopeNumber + 1; 101 this.node = node; 102 } 103 } 104 Context(Context ctx)105 public Context(Context ctx) { 106 this(ctx, (Node)null); 107 } 108 109 /** 110 * Declare local 111 */ declare(Environment env, LocalMember local)112 public int declare(Environment env, LocalMember local) { 113 //System.out.println( "DECLARE= " + local.getName() + "=" + varNumber + ", read=" + local.readcount + ", write=" + local.writecount + ", hash=" + local.hashCode()); 114 local.scopeNumber = scopeNumber; 115 if (this.field == null && idThis.equals(local.getName())) { 116 local.scopeNumber += 1; // Anticipate variable or initializer. 117 } 118 if (local.isInnerClass()) { 119 local.prev = classes; 120 classes = local; 121 return 0; 122 } 123 124 // Originally the statement: 125 // 126 // local.subModifiers(M_INLINEABLE); 127 // 128 // was here with the comment: 129 // 130 // // prevent inlining across call sites 131 // 132 // This statement prevented constant local variables from 133 // inlining. It didn't seem to do anything useful. 134 // 135 // The statement has been removed and an assertion has been 136 // added which mandates that the only members which are marked 137 // with M_INLINEABLE are the ones for which isConstant() is true. 138 // (Fix for 4106244.) 139 // 140 // Addition to the above comment: they might also be 141 // final variables initialized with 'this', 'super', or other 142 // final identifiers. See VarDeclarationStatement.inline(). 143 // So I've removed the assertion. The original subModifiers 144 // call appears to have been there to fix nested class translation 145 // breakage, which has been fixed in VarDeclarationStatement 146 // now instead. (Fix for 4073244.) 147 148 local.prev = locals; 149 locals = local; 150 local.number = varNumber; 151 varNumber += local.getType().stackSize(); 152 return local.number; 153 } 154 155 /** 156 * Get a local variable by name 157 */ 158 public getLocalField(Identifier name)159 LocalMember getLocalField(Identifier name) { 160 for (LocalMember f = locals ; f != null ; f = f.prev) { 161 if (name.equals(f.getName())) { 162 return f; 163 } 164 } 165 return null; 166 } 167 168 /** 169 * Get the scope number for a reference to a member of this class 170 * (Larger scope numbers are more deeply nested.) 171 * @see LocalMember#scopeNumber 172 */ 173 public getScopeNumber(ClassDefinition c)174 int getScopeNumber(ClassDefinition c) { 175 for (Context ctx = this; ctx != null; ctx = ctx.prev) { 176 if (ctx.field == null) continue; 177 if (ctx.field.getClassDefinition() == c) { 178 return ctx.frameNumber; 179 } 180 } 181 return -1; 182 } 183 184 private getFieldCommon(Environment env, Identifier name, boolean apparentOnly)185 MemberDefinition getFieldCommon(Environment env, Identifier name, 186 boolean apparentOnly) throws AmbiguousMember, ClassNotFound { 187 // Note: This is structured as a pair of parallel lookups. 188 // If we were to redesign Context, we might prefer to walk 189 // along a single chain of scopes. 190 191 LocalMember lf = getLocalField(name); 192 int ls = (lf == null) ? -2 : lf.scopeNumber; 193 194 ClassDefinition thisClass = field.getClassDefinition(); 195 196 // Also look for a class member in a shallower scope. 197 for (ClassDefinition c = thisClass; 198 c != null; 199 c = c.getOuterClass()) { 200 MemberDefinition f = c.getVariable(env, name, thisClass); 201 if (f != null && getScopeNumber(c) > ls) { 202 if (apparentOnly && f.getClassDefinition() != c) { 203 continue; 204 } 205 return f; 206 } 207 } 208 209 return lf; 210 } 211 212 /** 213 * Assign a number to a class field. 214 * (This is used to track definite assignment of some blank finals.) 215 */ declareFieldNumber(MemberDefinition field)216 public int declareFieldNumber(MemberDefinition field) { 217 return declare(null, new LocalMember(field)); 218 } 219 220 /** 221 * Retrieve a number previously assigned by declareMember(). 222 * Return -1 if there was no such assignment in this context. 223 */ getFieldNumber(MemberDefinition field)224 public int getFieldNumber(MemberDefinition field) { 225 for (LocalMember f = locals ; f != null ; f = f.prev) { 226 if (f.getMember() == field) { 227 return f.number; 228 } 229 } 230 return -1; 231 } 232 233 /** 234 * Return the local field or member field corresponding to a number. 235 * Return null if there is no such field. 236 */ getElement(int number)237 public MemberDefinition getElement(int number) { 238 for (LocalMember f = locals ; f != null ; f = f.prev) { 239 if (f.number == number) { 240 MemberDefinition field = f.getMember(); 241 return (field != null) ? field : f; 242 } 243 } 244 return null; 245 } 246 247 /** 248 * Get a local class by name 249 */ 250 public getLocalClass(Identifier name)251 LocalMember getLocalClass(Identifier name) { 252 for (LocalMember f = classes ; f != null ; f = f.prev) { 253 if (name.equals(f.getName())) { 254 return f; 255 } 256 } 257 return null; 258 } 259 260 private getClassCommon(Environment env, Identifier name, boolean apparentOnly)261 MemberDefinition getClassCommon(Environment env, Identifier name, 262 boolean apparentOnly) throws ClassNotFound { 263 LocalMember lf = getLocalClass(name); 264 int ls = (lf == null) ? -2 : lf.scopeNumber; 265 266 // Also look for a class member in a shallower scope. 267 for (ClassDefinition c = field.getClassDefinition(); 268 c != null; 269 c = c.getOuterClass()) { 270 // QUERY: We may need to get the inner class from a 271 // superclass of 'c'. This call is prepared to 272 // resolve the superclass if necessary. Can we arrange 273 // to assure that it is always previously resolved? 274 // This is one of a small number of problematic calls that 275 // requires 'getSuperClass' to resolve superclasses on demand. 276 // See 'ClassDefinition.getInnerClass(env, nm)'. 277 MemberDefinition f = c.getInnerClass(env, name); 278 if (f != null && getScopeNumber(c) > ls) { 279 if (apparentOnly && f.getClassDefinition() != c) { 280 continue; 281 } 282 return f; 283 } 284 } 285 286 return lf; 287 } 288 289 /** 290 * Get either a local variable, or a field in a current class 291 */ 292 public final getField(Environment env, Identifier name)293 MemberDefinition getField(Environment env, Identifier name) throws AmbiguousMember, ClassNotFound { 294 return getFieldCommon(env, name, false); 295 } 296 297 /** 298 * Like getField, except that it skips over inherited fields. 299 * Used for error checking. 300 */ 301 public final getApparentField(Environment env, Identifier name)302 MemberDefinition getApparentField(Environment env, Identifier name) throws AmbiguousMember, ClassNotFound { 303 return getFieldCommon(env, name, true); 304 } 305 306 /** 307 * Check if the given field is active in this context. 308 */ isInScope(LocalMember field)309 public boolean isInScope(LocalMember field) { 310 for (LocalMember f = locals ; f != null ; f = f.prev) { 311 if (field == f) { 312 return true; 313 } 314 } 315 return false; 316 } 317 318 /** 319 * Notice a reference (usually an uplevel one). 320 * Update the references list of every enclosing class 321 * which is enclosed by the scope of the target. 322 * Update decisions about which uplevels to make into fields. 323 * Return the uplevel reference descriptor, or null if it's local. 324 * <p> 325 * The target must be in scope in this context. 326 * So, call this method only from the check phase. 327 * (In other phases, the context may be less complete.) 328 * <p> 329 * This can and should be called both before and after classes are frozen. 330 * It should be a no-op, and will raise a compiler error if not. 331 */ noteReference(Environment env, LocalMember target)332 public UplevelReference noteReference(Environment env, LocalMember target) { 333 int targetScopeNumber = !isInScope(target) ? -1 : target.scopeNumber; 334 335 // Walk outward visiting each scope. 336 // Note each distinct frame (i.e., enclosing method). 337 // For each frame in which the variable is uplevel, 338 // record the event in the references list of the enclosing class. 339 UplevelReference res = null; 340 int currentFrameNumber = -1; 341 for (Context refctx = this; refctx != null; refctx = refctx.prev) { 342 if (currentFrameNumber == refctx.frameNumber) { 343 continue; // we're processing frames, not contexts 344 } 345 currentFrameNumber = refctx.frameNumber; 346 if (targetScopeNumber >= currentFrameNumber) { 347 break; // the target is native to this frame 348 } 349 350 // process a frame which is using this variable as an uplevel 351 ClassDefinition refc = refctx.field.getClassDefinition(); 352 UplevelReference r = refc.getReference(target); 353 r.noteReference(env, refctx); 354 355 // remember the reference pertaining to the innermost frame 356 if (res == null) { 357 res = r; 358 } 359 } 360 return res; 361 } 362 363 /** 364 * Implement a reference (usually an uplevel one). 365 * Call noteReference() first, to make sure the reference 366 * lists are up to date. 367 * <p> 368 * The resulting expression tree does not need checking; 369 * it can be code-generated right away. 370 * If the reference is not uplevel, the result is an IDENT or THIS. 371 */ makeReference(Environment env, LocalMember target)372 public Expression makeReference(Environment env, LocalMember target) { 373 UplevelReference r = noteReference(env, target); 374 375 // Now create a referencing expression. 376 if (r != null) { 377 return r.makeLocalReference(env, this); 378 } else if (idThis.equals(target.getName())) { 379 return new ThisExpression(0, target); 380 } else { 381 return new IdentifierExpression(0, target); 382 } 383 } 384 385 /** 386 * Return a local expression which can serve as the base reference 387 * for the given field. If the field is a constructor, return an 388 * expression for the implicit enclosing instance argument. 389 * <p> 390 * Return null if there is no need for such an argument, 391 * or if there was an error. 392 */ findOuterLink(Environment env, long where, MemberDefinition f)393 public Expression findOuterLink(Environment env, long where, 394 MemberDefinition f) { 395 // reqc is the base pointer type required to use f 396 ClassDefinition fc = f.getClassDefinition(); 397 ClassDefinition reqc = f.isStatic() ? null 398 : !f.isConstructor() ? fc 399 : fc.isTopLevel() ? null 400 : fc.getOuterClass(); 401 if (reqc == null) { 402 return null; 403 } 404 return findOuterLink(env, where, reqc, f, false); 405 } 406 match(Environment env, ClassDefinition thisc, ClassDefinition reqc)407 private static boolean match(Environment env, 408 ClassDefinition thisc, ClassDefinition reqc) { 409 try { 410 return thisc == reqc 411 || reqc.implementedBy(env, thisc.getClassDeclaration()); 412 } catch (ClassNotFound ee) { 413 return false; 414 } 415 } 416 findOuterLink(Environment env, long where, ClassDefinition reqc, MemberDefinition f, boolean needExactMatch)417 public Expression findOuterLink(Environment env, long where, 418 ClassDefinition reqc, 419 MemberDefinition f, 420 boolean needExactMatch) { 421 if (field.isStatic()) { 422 if (f == null) { 423 // say something like: undefined variable A.this 424 Identifier nm = reqc.getName().getFlatName().getName(); 425 env.error(where, "undef.var", Identifier.lookup(nm,idThis)); 426 } else if (f.isConstructor()) { 427 env.error(where, "no.outer.arg", reqc, f.getClassDeclaration()); 428 } else if (f.isMethod()) { 429 env.error(where, "no.static.meth.access", 430 f, f.getClassDeclaration()); 431 } else { 432 env.error(where, "no.static.field.access", f.getName(), 433 f.getClassDeclaration()); 434 } 435 // This is an attempt at error recovery. 436 // Unfortunately, the constructor may throw 437 // a null pointer exception after failing to resolve 438 // 'idThis'. Since an error message has already been 439 // issued previously, this exception is caught and 440 // silently ignored. Ideally, we should avoid throwing 441 // the exception. 442 Expression e = new ThisExpression(where, this); 443 e.type = reqc.getType(); 444 return e; 445 } 446 447 // use lp to scan for current instances (locals named "this") 448 LocalMember lp = locals; 449 450 // thise is a link expression being built up 451 Expression thise = null; 452 453 // root is the local variable (idThis) at the far left of thise 454 LocalMember root = null; 455 456 // thisc is the class of the link expression thise 457 ClassDefinition thisc = null; 458 459 // conCls is the class of the "this", in a constructor 460 ClassDefinition conCls = null; 461 if (field.isConstructor()) { 462 conCls = field.getClassDefinition(); 463 } 464 465 if (!field.isMethod()) { 466 thisc = field.getClassDefinition(); 467 thise = new ThisExpression(where, this); 468 } 469 470 while (true) { 471 if (thise == null) { 472 // start fresh from lp 473 while (lp != null && !idThis.equals(lp.getName())) { 474 lp = lp.prev; 475 } 476 if (lp == null) { 477 break; 478 } 479 thise = new ThisExpression(where, lp); 480 thisc = lp.getClassDefinition(); 481 root = lp; 482 lp = lp.prev; 483 } 484 485 // Require exact class identity when called with 486 // 'needExactMatch' true. This is done when checking 487 // the '<class>.this' syntax. Fixes 4102393 and 4133457. 488 if (thisc == reqc || 489 (!needExactMatch && match(env, thisc, reqc))) { 490 break; 491 } 492 493 // move out one step, if the current instance has an outer link 494 495 MemberDefinition outerMember = thisc.findOuterMember(); 496 if (outerMember == null) { 497 thise = null; 498 continue; // try to find more help in lp 499 } 500 ClassDefinition prevc = thisc; 501 thisc = prevc.getOuterClass(); 502 503 if (prevc == conCls) { 504 // Must pick up "this$C" from the constructor argument, 505 // not from "this.this$C", since the latter may not be 506 // initialized properly. (This way is cheaper too.) 507 Identifier nm = outerMember.getName(); 508 IdentifierExpression arg = new IdentifierExpression(where, nm); 509 arg.bind(env, this); 510 thise = arg; 511 } else { 512 thise = new FieldExpression(where, thise, outerMember); 513 } 514 } 515 if (thise != null) { 516 // mark crossed scopes 517 // ????? 518 //ensureAvailable(root); 519 return thise; 520 } 521 522 if (f == null) { 523 // say something like: undefined variable A.this 524 Identifier nm = reqc.getName().getFlatName().getName(); 525 env.error(where, "undef.var", Identifier.lookup(nm,idThis)); 526 } else if (f.isConstructor()) { 527 env.error(where, "no.outer.arg", reqc, f.getClassDefinition()); 528 } else { 529 env.error(where, "no.static.field.access", f, field); 530 } 531 532 // avoid floodgating: 533 Expression e = new ThisExpression(where, this); 534 e.type = reqc.getType(); 535 return e; 536 } 537 538 /** 539 * Is there a "this" of type reqc in scope? 540 */ outerLinkExists(Environment env, ClassDefinition reqc, ClassDefinition thisc)541 public static boolean outerLinkExists(Environment env, 542 ClassDefinition reqc, 543 ClassDefinition thisc) { 544 while (!match(env, thisc, reqc)) { 545 if (thisc.isTopLevel()) { 546 return false; 547 } 548 thisc = thisc.getOuterClass(); 549 } 550 return true; 551 } 552 553 /** 554 * From which enclosing class do members of this type come? 555 */ findScope(Environment env, ClassDefinition reqc)556 public ClassDefinition findScope(Environment env, ClassDefinition reqc) { 557 ClassDefinition thisc = field.getClassDefinition(); 558 while (thisc != null && !match(env, thisc, reqc)) { 559 thisc = thisc.getOuterClass(); 560 } 561 return thisc; 562 } 563 564 /** 565 * Resolve a type name from within a local scope. 566 * @see Environment#resolveName 567 */ resolveName(Environment env, Identifier name)568 Identifier resolveName(Environment env, Identifier name) { 569 // This logic is pretty much exactly parallel to that of 570 // Environment.resolveName(). 571 if (name.isQualified()) { 572 // Try to resolve the first identifier component, 573 // because inner class names take precedence over 574 // package prefixes. (Cf. Environment.resolveName.) 575 Identifier rhead = resolveName(env, name.getHead()); 576 577 if (rhead.hasAmbigPrefix()) { 578 // The first identifier component refers to an 579 // ambiguous class. Limp on. We throw away the 580 // rest of the classname as it is irrelevant. 581 // (part of solution for 4059855). 582 return rhead; 583 } 584 585 if (!env.classExists(rhead)) { 586 return env.resolvePackageQualifiedName(name); 587 } 588 try { 589 return env.getClassDefinition(rhead). 590 resolveInnerClass(env, name.getTail()); 591 } catch (ClassNotFound ee) { 592 // return partially-resolved name someone else can fail on 593 return Identifier.lookupInner(rhead, name.getTail()); 594 } 595 } 596 597 // Look for an unqualified name in enclosing scopes. 598 try { 599 MemberDefinition f = getClassCommon(env, name, false); 600 if (f != null) { 601 return f.getInnerClass().getName(); 602 } 603 } catch (ClassNotFound ee) { 604 // a missing superclass, or something catastrophic 605 } 606 607 // look in imports, etc. 608 return env.resolveName(name); 609 } 610 611 /** 612 * Return the name of a lexically apparent type, 613 * skipping inherited members, and ignoring 614 * the current pacakge and imports. 615 * This is used for error checking. 616 */ 617 public getApparentClassName(Environment env, Identifier name)618 Identifier getApparentClassName(Environment env, Identifier name) { 619 if (name.isQualified()) { 620 // Try to resolve the first identifier component, 621 // because inner class names take precedence over 622 // package prefixes. (Cf. Environment.resolveName.) 623 Identifier rhead = getApparentClassName(env, name.getHead()); 624 return (rhead == null) ? idNull 625 : Identifier.lookup(rhead, 626 name.getTail()); 627 } 628 629 // Look for an unqualified name in enclosing scopes. 630 try { 631 MemberDefinition f = getClassCommon(env, name, true); 632 if (f != null) { 633 return f.getInnerClass().getName(); 634 } 635 } catch (ClassNotFound ee) { 636 // a missing superclass, or something catastrophic 637 } 638 639 // the enclosing class name is the only apparent package member: 640 Identifier topnm = field.getClassDefinition().getTopClass().getName(); 641 if (topnm.getName().equals(name)) { 642 return topnm; 643 } 644 return idNull; 645 } 646 647 /** 648 * Raise an error if a blank final was definitely unassigned 649 * on entry to a loop, but has possibly been assigned on the 650 * back-branch. If this is the case, the loop may be assigning 651 * it multiple times. 652 */ checkBackBranch(Environment env, Statement loop, Vset vsEntry, Vset vsBack)653 public void checkBackBranch(Environment env, Statement loop, 654 Vset vsEntry, Vset vsBack) { 655 for (LocalMember f = locals ; f != null ; f = f.prev) { 656 if (f.isBlankFinal() 657 && vsEntry.testVarUnassigned(f.number) 658 && !vsBack.testVarUnassigned(f.number)) { 659 env.error(loop.where, "assign.to.blank.final.in.loop", 660 f.getName()); 661 } 662 } 663 } 664 665 /** 666 * Check if a field can reach another field (only considers 667 * forward references, not the access modifiers). 668 */ canReach(Environment env, MemberDefinition f)669 public boolean canReach(Environment env, MemberDefinition f) { 670 return field.canReach(env, f); 671 } 672 673 /** 674 * Get the context that corresponds to a label, return null if 675 * not found. 676 */ 677 public getLabelContext(Identifier lbl)678 Context getLabelContext(Identifier lbl) { 679 for (Context ctx = this ; ctx != null ; ctx = ctx.prev) { 680 if ((ctx.node != null) && (ctx.node instanceof Statement)) { 681 if (((Statement)(ctx.node)).hasLabel(lbl)) 682 return ctx; 683 } 684 } 685 return null; 686 } 687 688 /** 689 * Get the destination context of a break 690 */ 691 public getBreakContext(Identifier lbl)692 Context getBreakContext(Identifier lbl) { 693 if (lbl != null) { 694 return getLabelContext(lbl); 695 } 696 for (Context ctx = this ; ctx != null ; ctx = ctx.prev) { 697 if (ctx.node != null) { 698 switch (ctx.node.op) { 699 case SWITCH: 700 case FOR: 701 case DO: 702 case WHILE: 703 return ctx; 704 } 705 } 706 } 707 return null; 708 } 709 710 /** 711 * Get the destination context of a continue 712 */ 713 public getContinueContext(Identifier lbl)714 Context getContinueContext(Identifier lbl) { 715 if (lbl != null) { 716 return getLabelContext(lbl); 717 } 718 for (Context ctx = this ; ctx != null ; ctx = ctx.prev) { 719 if (ctx.node != null) { 720 switch (ctx.node.op) { 721 case FOR: 722 case DO: 723 case WHILE: 724 return ctx; 725 } 726 } 727 } 728 return null; 729 } 730 731 /** 732 * Get the destination context of a return (the method body) 733 */ 734 public getReturnContext()735 CheckContext getReturnContext() { 736 for (Context ctx = this ; ctx != null ; ctx = ctx.prev) { 737 // The METHOD node is set up by Statement.checkMethod(). 738 if (ctx.node != null && ctx.node.op == METHOD) { 739 return (CheckContext)ctx; 740 } 741 } 742 return null; 743 } 744 745 /** 746 * Get the context of the innermost surrounding try-block. 747 * Consider only try-blocks contained within the same method. 748 * (There could be others when searching from within a method 749 * of a local class, but they are irrelevant to our purpose.) 750 * This is used for recording DA/DU information preceding 751 * all abnormal transfers of control: break, continue, return, 752 * and throw. 753 */ 754 public getTryExitContext()755 CheckContext getTryExitContext() { 756 for (Context ctx = this; 757 ctx != null && ctx.node != null && ctx.node.op != METHOD; 758 ctx = ctx.prev) { 759 if (ctx.node.op == TRY) { 760 return (CheckContext)ctx; 761 } 762 } 763 return null; 764 } 765 766 /** 767 * Get the nearest inlined context 768 */ getInlineContext()769 Context getInlineContext() { 770 for (Context ctx = this ; ctx != null ; ctx = ctx.prev) { 771 if (ctx.node != null) { 772 switch (ctx.node.op) { 773 case INLINEMETHOD: 774 case INLINENEWINSTANCE: 775 return ctx; 776 } 777 } 778 } 779 return null; 780 } 781 782 /** 783 * Get the context of a field that is being inlined 784 */ getInlineMemberContext(MemberDefinition field)785 Context getInlineMemberContext(MemberDefinition field) { 786 for (Context ctx = this ; ctx != null ; ctx = ctx.prev) { 787 if (ctx.node != null) { 788 switch (ctx.node.op) { 789 case INLINEMETHOD: 790 if (((InlineMethodExpression)ctx.node).field.equals(field)) { 791 return ctx; 792 } 793 break; 794 case INLINENEWINSTANCE: 795 if (((InlineNewInstanceExpression)ctx.node).field.equals(field)) { 796 return ctx; 797 } 798 } 799 } 800 } 801 return null; 802 } 803 804 /** 805 * Remove variables from the vset set that are no longer part of 806 * this context. 807 */ removeAdditionalVars(Vset vset)808 public final Vset removeAdditionalVars(Vset vset) { 809 return vset.removeAdditionalVars(varNumber); 810 } 811 getVarNumber()812 public final int getVarNumber() { 813 return varNumber; 814 } 815 816 /** 817 * Return the number of the innermost current instance reference. 818 */ getThisNumber()819 public int getThisNumber() { 820 LocalMember thisf = getLocalField(idThis); 821 if (thisf != null 822 && thisf.getClassDefinition() == field.getClassDefinition()) { 823 return thisf.number; 824 } 825 // this is a variable; there is no "this" (should not happen) 826 return varNumber; 827 } 828 829 /** 830 * Return the field containing the present context. 831 */ getField()832 public final MemberDefinition getField() { 833 return field; 834 } 835 836 /** 837 * Extend an environment with the given context. 838 * The resulting environment behaves the same as 839 * the given one, except that resolveName() takes 840 * into account local class names in this context. 841 */ newEnvironment(Environment env, Context ctx)842 public static Environment newEnvironment(Environment env, Context ctx) { 843 return new ContextEnvironment(env, ctx); 844 } 845 } 846 847 final 848 class ContextEnvironment extends Environment { 849 Context ctx; 850 Environment innerEnv; 851 ContextEnvironment(Environment env, Context ctx)852 ContextEnvironment(Environment env, Context ctx) { 853 super(env, env.getSource()); 854 this.ctx = ctx; 855 this.innerEnv = env; 856 } 857 resolveName(Identifier name)858 public Identifier resolveName(Identifier name) { 859 return ctx.resolveName(innerEnv, name); 860 } 861 } 862