1 /* 2 * Copyright (c) 1994, 2004, 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.javac; 27 28 import sun.tools.java.*; 29 import sun.tools.tree.*; 30 import sun.tools.asm.*; 31 import java.util.Vector; 32 import java.util.Enumeration; 33 import java.util.Hashtable; 34 import java.io.PrintStream; 35 36 /** 37 * A Source Member 38 * 39 * WARNING: The contents of this source file are not part of any 40 * supported API. Code that depends on them does so at its own risk: 41 * they are subject to change or removal without notice. 42 */ 43 @Deprecated 44 public 45 class SourceMember extends MemberDefinition implements Constants { 46 /** 47 * The argument names (if it is a method) 48 */ 49 Vector<MemberDefinition> args; 50 51 // set to the MemberDefinition in the interface if we have this field because 52 // it has been forced on us 53 MemberDefinition abstractSource; 54 55 /** 56 * The status of the field 57 */ 58 int status; 59 60 static final int PARSED = 0; 61 static final int CHECKING = 1; 62 static final int CHECKED = 2; 63 static final int INLINING = 3; 64 static final int INLINED = 4; 65 static final int ERROR = 5; 66 getArguments()67 public Vector<MemberDefinition> getArguments() { 68 return args; 69 } 70 71 /** 72 * Constructor 73 * @param argNames a vector of IdentifierToken 74 */ SourceMember(long where, ClassDefinition clazz, String doc, int modifiers, Type type, Identifier name, Vector<MemberDefinition> argNames, IdentifierToken exp[], Node value)75 public SourceMember(long where, ClassDefinition clazz, 76 String doc, int modifiers, Type type, 77 Identifier name, Vector<MemberDefinition> argNames, 78 IdentifierToken exp[], Node value) { 79 super(where, clazz, modifiers, type, name, exp, value); 80 this.documentation = doc; 81 this.args = argNames; // for the moment 82 // not until type names are resolved: createArgumentFields(argNames); 83 84 if (ClassDefinition.containsDeprecated(documentation)) { 85 this.modifiers |= M_DEPRECATED; 86 } 87 } 88 createArgumentFields(Vector<MemberDefinition> argNames)89 void createArgumentFields(Vector<MemberDefinition> argNames) { 90 // Create a list of arguments 91 if (isMethod()) { 92 args = new Vector<>(); 93 94 if (isConstructor() || !(isStatic() || isInitializer())) { 95 args.addElement(((SourceClass)clazz).getThisArgument()); 96 } 97 98 if (argNames != null) { 99 Enumeration<MemberDefinition> e = argNames.elements(); 100 Type argTypes[] = getType().getArgumentTypes(); 101 for (int i = 0 ; i < argTypes.length ; i++) { 102 Object x = e.nextElement(); 103 if (x instanceof LocalMember) { 104 // This should not happen, but it does 105 // in cases of vicious cyclic inheritance. 106 args = argNames; 107 return; 108 } 109 Identifier id; 110 int mod; 111 long where; 112 if (x instanceof Identifier) { 113 // allow argNames to be simple Identifiers (deprecated!) 114 id = (Identifier)x; 115 mod = 0; 116 where = getWhere(); 117 } else { 118 IdentifierToken token = (IdentifierToken)x; 119 id = token.getName(); 120 mod = token.getModifiers(); 121 where = token.getWhere(); 122 } 123 args.addElement(new LocalMember(where, clazz, mod, 124 argTypes[i], id)); 125 } 126 } 127 } 128 } 129 130 // The methods addOuterThis() and addUplevelArguments() were 131 // both originally part of a single method called addUplevelArguments() 132 // which took a single boolean parameter describing which of the 133 // two behaviors it wanted. 134 // 135 // The original addUplevelArguments() claimed to keep the arguments in 136 // the following order: 137 // 138 // (1) <this> <early outer this> <uplevel arguments...> <true arguments...> 139 // 140 // (By <early outer this> I am referring to the clientOuterField added 141 // to some constructors when they are created. If an outer this is 142 // added later, on demand, then this is mixed in with the rest of the 143 // uplevel arguments and is added by addUplevelArguments.) 144 // 145 // In reality, the `args' Vector was generated in this order, but the 146 // Type array `argTypes' was generated as: 147 // 148 // (2) <this> <uplevel arguments...> <early outer this> <true arguments...> 149 // 150 // This didn't make a difference in the common case -- that is, when 151 // a class had an <outer.this> or <uplevel arguments...> but not both. 152 // Both can happen in the case that a member class is declared inside 153 // of a local class. It seems that the calling sequences, generated 154 // in places like NewInstanceExpression.codeCommon(), use order (2), 155 // so I have changed the code below to stick with that order. Since 156 // the only time this happens is in classes which are insideLocal, no 157 // one should be able to tell the difference between these orders. 158 // (bug number 4085633) 159 160 LocalMember outerThisArg = null; 161 162 /** 163 * Get outer instance link, or null if none. 164 */ 165 getOuterThisArg()166 public LocalMember getOuterThisArg() { 167 return outerThisArg; 168 } 169 170 /** 171 * Add the outer.this argument to the list of arguments for this 172 * constructor. This is called from resolveTypeStructure. Any 173 * additional uplevel arguments get added later by addUplevelArguments(). 174 */ 175 addOuterThis()176 void addOuterThis() { 177 UplevelReference refs = clazz.getReferences(); 178 179 // See if we have a client outer field. 180 while (refs != null && 181 !refs.isClientOuterField()) { 182 refs = refs.getNext(); 183 } 184 185 // There is no outer this argument. Quit. 186 if (refs == null) { 187 return; 188 } 189 190 // Get the old arg types. 191 Type oldArgTypes[] = type.getArgumentTypes(); 192 193 // And make an array for the new ones with space for one more. 194 Type argTypes[] = new Type[oldArgTypes.length + 1]; 195 196 LocalMember arg = refs.getLocalArgument(); 197 outerThisArg = arg; 198 199 // args is our list of arguments. It contains a `this', so 200 // we insert at position 1. The list of types does not have a 201 // this, so we insert at position 0. 202 args.insertElementAt(arg, 1); 203 argTypes[0] = arg.getType(); 204 205 // Add on the rest of the constructor arguments. 206 for (int i = 0; i < oldArgTypes.length; i++) { 207 argTypes[i + 1] = oldArgTypes[i]; 208 } 209 210 type = Type.tMethod(type.getReturnType(), argTypes); 211 } 212 213 /** 214 * Prepend argument names and argument types for local variable references. 215 * This information is never seen by the type-check phase, 216 * but it affects code generation, which is the earliest moment 217 * we have comprehensive information on uplevel references. 218 * The code() methods tweaks the constructor calls, prepending 219 * the proper values to the argument list. 220 */ addUplevelArguments()221 void addUplevelArguments() { 222 UplevelReference refs = clazz.getReferences(); 223 clazz.getReferencesFrozen(); 224 225 // Count how many uplevels we have to add. 226 int count = 0; 227 for (UplevelReference r = refs; r != null; r = r.getNext()) { 228 if (!r.isClientOuterField()) { 229 count += 1; 230 } 231 } 232 233 if (count == 0) { 234 // None to add, quit. 235 return; 236 } 237 238 // Get the old argument types. 239 Type oldArgTypes[] = type.getArgumentTypes(); 240 241 // Make an array with enough room for the new. 242 Type argTypes[] = new Type[oldArgTypes.length + count]; 243 244 // Add all of the late uplevel references to args and argTypes. 245 // Note that they are `off-by-one' because of the `this'. 246 int ins = 0; 247 for (UplevelReference r = refs; r != null; r = r.getNext()) { 248 if (!r.isClientOuterField()) { 249 LocalMember arg = r.getLocalArgument(); 250 251 args.insertElementAt(arg, 1 + ins); 252 argTypes[ins] = arg.getType(); 253 254 ins++; 255 } 256 } 257 258 // Add the rest of the old arguments. 259 for (int i = 0; i < oldArgTypes.length; i++) { 260 argTypes[ins + i] = oldArgTypes[i]; 261 } 262 263 type = Type.tMethod(type.getReturnType(), argTypes); 264 } 265 266 /** 267 * Constructor for an inner class. 268 */ SourceMember(ClassDefinition innerClass)269 public SourceMember(ClassDefinition innerClass) { 270 super(innerClass); 271 } 272 273 /** 274 * Constructor. 275 * Used only to generate an abstract copy of a method that a class 276 * inherits from an interface 277 */ SourceMember(MemberDefinition f, ClassDefinition c, Environment env)278 public SourceMember(MemberDefinition f, ClassDefinition c, Environment env) { 279 this(f.getWhere(), c, f.getDocumentation(), 280 f.getModifiers() | M_ABSTRACT, f.getType(), f.getName(), null, 281 f.getExceptionIds(), null); 282 this.args = f.getArguments(); 283 this.abstractSource = f; 284 this.exp = f.getExceptions(env); 285 } 286 287 /** 288 * Get exceptions 289 */ getExceptions(Environment env)290 public ClassDeclaration[] getExceptions(Environment env) { 291 if ((!isMethod()) || (exp != null)) { 292 return exp; 293 } 294 if (expIds == null) { 295 // (should not happen) 296 exp = new ClassDeclaration[0]; 297 return exp; 298 } 299 // be sure to get the imports right: 300 env = ((SourceClass)getClassDefinition()).setupEnv(env); 301 exp = new ClassDeclaration[expIds.length]; 302 for (int i = 0; i < exp.length; i++) { 303 Identifier e = expIds[i].getName(); 304 Identifier rexp = getClassDefinition().resolveName(env, e); 305 exp[i] = env.getClassDeclaration(rexp); 306 } 307 return exp; 308 } 309 310 /** 311 * Set array of name-resolved exceptions directly, e.g., for access methods. 312 */ setExceptions(ClassDeclaration[] exp)313 public void setExceptions(ClassDeclaration[] exp) { 314 this.exp = exp; 315 } 316 317 /** 318 * Resolve types in a field, after parsing. 319 * @see ClassDefinition.resolveTypeStructure 320 */ 321 322 public boolean resolved = false; 323 resolveTypeStructure(Environment env)324 public void resolveTypeStructure(Environment env) { 325 if (tracing) env.dtEnter("SourceMember.resolveTypeStructure: " + this); 326 327 // A member should only be resolved once. For a constructor, it is imperative 328 // that 'addOuterThis' be called only once, else the outer instance argument may 329 // be inserted into the argument list multiple times. 330 331 if (resolved) { 332 if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: OK " + this); 333 // This case shouldn't be happening. It is the responsibility 334 // of our callers to avoid attempting multiple resolutions of a member. 335 // *** REMOVE FOR SHIPMENT? *** 336 throw new CompilerError("multiple member type resolution"); 337 //return; 338 } else { 339 if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: RESOLVING " + this); 340 resolved = true; 341 } 342 343 super.resolveTypeStructure(env); 344 if (isInnerClass()) { 345 ClassDefinition nc = getInnerClass(); 346 if (nc instanceof SourceClass && !nc.isLocal()) { 347 ((SourceClass)nc).resolveTypeStructure(env); 348 } 349 type = innerClass.getType(); 350 } else { 351 // Expand all class names in 'type', including those that are not 352 // fully-qualified or refer to inner classes, into fully-qualified 353 // names. Local and anonymous classes get synthesized names here, 354 // corresponding to the class files that will be generated. This is 355 // currently the only place where 'resolveNames' is used. 356 type = env.resolveNames(getClassDefinition(), type, isSynthetic()); 357 358 // do the throws also: 359 getExceptions(env); 360 361 if (isMethod()) { 362 Vector<MemberDefinition> argNames = args; args = null; 363 createArgumentFields(argNames); 364 // Add outer instance argument for constructors. 365 if (isConstructor()) { 366 addOuterThis(); 367 } 368 } 369 } 370 if (tracing) env.dtExit("SourceMember.resolveTypeStructure: " + this); 371 } 372 373 /** 374 * Get the class declaration in which the field is actually defined 375 */ getDefiningClassDeclaration()376 public ClassDeclaration getDefiningClassDeclaration() { 377 if (abstractSource == null) 378 return super.getDefiningClassDeclaration(); 379 else 380 return abstractSource.getDefiningClassDeclaration(); 381 } 382 383 /** 384 * A source field never reports deprecation, since the compiler 385 * allows access to deprecated features that are being compiled 386 * in the same job. 387 */ reportDeprecated(Environment env)388 public boolean reportDeprecated(Environment env) { 389 return false; 390 } 391 392 /** 393 * Check this field. 394 * <p> 395 * This is the method which requests checking. 396 * The real work is done by 397 * {@code Vset check(Environment, Context, Vset)}. 398 */ check(Environment env)399 public void check(Environment env) throws ClassNotFound { 400 if (tracing) env.dtEnter("SourceMember.check: " + 401 getName() + ", status = " + status); 402 // rely on the class to check all fields in the proper order 403 if (status == PARSED) { 404 if (isSynthetic() && getValue() == null) { 405 // break a big cycle for small synthetic variables 406 status = CHECKED; 407 if (tracing) 408 env.dtExit("SourceMember.check: BREAKING CYCLE"); 409 return; 410 } 411 if (tracing) env.dtEvent("SourceMember.check: CHECKING CLASS"); 412 clazz.check(env); 413 if (status == PARSED) { 414 if (getClassDefinition().getError()) { 415 status = ERROR; 416 } else { 417 if (tracing) 418 env.dtExit("SourceMember.check: CHECK FAILED"); 419 throw new CompilerError("check failed"); 420 } 421 } 422 } 423 if (tracing) env.dtExit("SourceMember.check: DONE " + 424 getName() + ", status = " + status); 425 } 426 427 /** 428 * Check a field. 429 * @param vset tells which uplevel variables are definitely assigned 430 * The vset is also used to track the initialization of blank finals 431 * by whichever fields which are relevant to them. 432 */ check(Environment env, Context ctx, Vset vset)433 public Vset check(Environment env, Context ctx, Vset vset) throws ClassNotFound { 434 if (tracing) env.dtEvent("SourceMember.check: MEMBER " + 435 getName() + ", status = " + status); 436 if (status == PARSED) { 437 if (isInnerClass()) { 438 // some classes are checked separately 439 ClassDefinition nc = getInnerClass(); 440 if (nc instanceof SourceClass && !nc.isLocal() 441 && nc.isInsideLocal()) { 442 status = CHECKING; 443 vset = ((SourceClass)nc).checkInsideClass(env, ctx, vset); 444 } 445 status = CHECKED; 446 return vset; 447 } 448 if (env.dump()) { 449 System.out.println("[check field " + getClassDeclaration().getName() + "." + getName() + "]"); 450 if (getValue() != null) { 451 getValue().print(System.out); 452 System.out.println(); 453 } 454 } 455 env = new Environment(env, this); 456 457 // This is where all checking of names appearing within the type 458 // of the member is done. Includes return type and argument types. 459 // Since only one location ('where') for error messages is provided, 460 // localization of errors is poor. Throws clauses are handled below. 461 env.resolve(where, getClassDefinition(), getType()); 462 463 // Make sure that all the classes that we claim to throw really 464 // are subclasses of Throwable, and are classes that we can reach 465 if (isMethod()) { 466 ClassDeclaration throwable = 467 env.getClassDeclaration(idJavaLangThrowable); 468 ClassDeclaration exp[] = getExceptions(env); 469 for (int i = 0 ; i < exp.length ; i++) { 470 ClassDefinition def; 471 long where = getWhere(); 472 if (expIds != null && i < expIds.length) { 473 where = IdentifierToken.getWhere(expIds[i], where); 474 } 475 try { 476 def = exp[i].getClassDefinition(env); 477 478 // Validate access for all inner-class components 479 // of a qualified name, not just the last one, which 480 // is checked below. Yes, this is a dirty hack... 481 // Part of fix for 4094658. 482 env.resolveByName(where, getClassDefinition(), def.getName()); 483 484 } catch (ClassNotFound e) { 485 env.error(where, "class.not.found", e.name, "throws"); 486 break; 487 } 488 def.noteUsedBy(getClassDefinition(), where, env); 489 if (!getClassDefinition(). 490 canAccess(env, def.getClassDeclaration())) { 491 env.error(where, "cant.access.class", def); 492 } else if (!def.subClassOf(env, throwable)) { 493 env.error(where, "throws.not.throwable", def); 494 } 495 } 496 } 497 498 status = CHECKING; 499 500 if (isMethod() && args != null) { 501 int length = args.size(); 502 outer_loop: 503 for (int i = 0; i < length; i++) { 504 LocalMember lf = (LocalMember)(args.elementAt(i)); 505 Identifier name_i = lf.getName(); 506 for (int j = i + 1; j < length; j++) { 507 LocalMember lf2 = (LocalMember)(args.elementAt(j)); 508 Identifier name_j = lf2.getName(); 509 if (name_i.equals(name_j)) { 510 env.error(lf2.getWhere(), "duplicate.argument", 511 name_i); 512 break outer_loop; 513 } 514 } 515 } 516 } 517 518 if (getValue() != null) { 519 ctx = new Context(ctx, this); 520 521 if (isMethod()) { 522 Statement s = (Statement)getValue(); 523 // initialize vset, indication that each of the arguments 524 // to the function has a value 525 526 for (Enumeration<MemberDefinition> e = args.elements(); e.hasMoreElements();){ 527 LocalMember f = (LocalMember)e.nextElement(); 528 vset.addVar(ctx.declare(env, f)); 529 } 530 531 if (isConstructor()) { 532 // Undefine "this" in some constructors, until after 533 // the super constructor has been called. 534 vset.clearVar(ctx.getThisNumber()); 535 536 // If the first thing in the definition isn't a call 537 // to either super() or this(), then insert one. 538 Expression supCall = s.firstConstructor(); 539 if ((supCall == null) 540 && (getClassDefinition().getSuperClass() != null)) { 541 supCall = getDefaultSuperCall(env); 542 Statement scs = new ExpressionStatement(where, 543 supCall); 544 s = Statement.insertStatement(scs, s); 545 setValue(s); 546 } 547 } 548 549 //System.out.println("VSET = " + vset); 550 ClassDeclaration exp[] = getExceptions(env); 551 int htsize = (exp.length > 3) ? 17 : 7; 552 Hashtable<Object, Object> thrown = new Hashtable<>(htsize); 553 554 vset = s.checkMethod(env, ctx, vset, thrown); 555 556 ClassDeclaration ignore1 = 557 env.getClassDeclaration(idJavaLangError); 558 ClassDeclaration ignore2 = 559 env.getClassDeclaration(idJavaLangRuntimeException); 560 561 for (Enumeration<Object> e = thrown.keys(); e.hasMoreElements();) { 562 ClassDeclaration c = (ClassDeclaration)e.nextElement(); 563 ClassDefinition def = c.getClassDefinition(env); 564 if (def.subClassOf(env, ignore1) 565 || def.subClassOf(env, ignore2)) { 566 continue; 567 } 568 569 boolean ok = false; 570 if (!isInitializer()) { 571 for (int i = 0 ; i < exp.length ; i++) { 572 if (def.subClassOf(env, exp[i])) { 573 ok = true; 574 } 575 } 576 } 577 if (!ok) { 578 Node n = (Node)thrown.get(c); 579 long where = n.getWhere(); 580 String errorMsg; 581 582 if (isConstructor()) { 583 if (where == 584 getClassDefinition().getWhere()) { 585 586 // If this message is being generated for 587 // a default constructor, we should give 588 // a different error message. Currently 589 // we check for this by seeing if the 590 // constructor has the same "where" as 591 // its class. This is a bit kludgy, but 592 // works. (bug id 4034836) 593 errorMsg = "def.constructor.exception"; 594 } else { 595 // Constructor with uncaught exception. 596 errorMsg = "constructor.exception"; 597 } 598 } else if (isInitializer()) { 599 // Initializer with uncaught exception. 600 errorMsg = "initializer.exception"; 601 } else { 602 // Method with uncaught exception. 603 errorMsg = "uncaught.exception"; 604 } 605 env.error(where, errorMsg, c.getName()); 606 } 607 } 608 } else { 609 Hashtable<Object, Object> thrown = new Hashtable<>(3); // small & throw-away 610 Expression val = (Expression)getValue(); 611 612 vset = val.checkInitializer(env, ctx, vset, 613 getType(), thrown); 614 setValue(val.convert(env, ctx, getType(), val)); 615 616 // Complain about static final members of inner classes that 617 // do not have an initializer that is a constant expression. 618 // In general, static members are not permitted for inner 619 // classes, but an exception is made for named constants. 620 // Other cases of static members, including non-final ones, 621 // are handled in 'SourceClass'. Part of fix for 4095568. 622 if (isStatic() && isFinal() && !clazz.isTopLevel()) { 623 if (!((Expression)getValue()).isConstant()) { 624 env.error(where, "static.inner.field", getName(), this); 625 setValue(null); 626 } 627 } 628 629 630 // Both RuntimeExceptions and Errors should be 631 // allowed in initializers. Fix for bug 4102541. 632 ClassDeclaration except = 633 env.getClassDeclaration(idJavaLangThrowable); 634 ClassDeclaration ignore1 = 635 env.getClassDeclaration(idJavaLangError); 636 ClassDeclaration ignore2 = 637 env.getClassDeclaration(idJavaLangRuntimeException); 638 639 for (Enumeration<Object> e = thrown.keys(); e.hasMoreElements(); ) { 640 ClassDeclaration c = (ClassDeclaration)e.nextElement(); 641 ClassDefinition def = c.getClassDefinition(env); 642 643 if (!def.subClassOf(env, ignore1) 644 && !def.subClassOf(env, ignore2) 645 && def.subClassOf(env, except)) { 646 Node n = (Node)thrown.get(c); 647 env.error(n.getWhere(), 648 "initializer.exception", c.getName()); 649 } 650 } 651 } 652 if (env.dump()) { 653 getValue().print(System.out); 654 System.out.println(); 655 } 656 } 657 status = getClassDefinition().getError() ? ERROR : CHECKED; 658 } 659 660 661 // Initializers (static and instance) must be able to complete normally. 662 if (isInitializer() && vset.isDeadEnd()) { 663 env.error(where, "init.no.normal.completion"); 664 vset = vset.clearDeadEnd(); 665 } 666 667 return vset; 668 } 669 670 // helper to check(): synthesize a missing super() call getDefaultSuperCall(Environment env)671 private Expression getDefaultSuperCall(Environment env) { 672 Expression se = null; 673 ClassDefinition sclass = getClassDefinition().getSuperClass().getClassDefinition(); 674 // does the superclass constructor require an enclosing instance? 675 ClassDefinition reqc = (sclass == null) ? null 676 : sclass.isTopLevel() ? null 677 : sclass.getOuterClass(); 678 ClassDefinition thisc = getClassDefinition(); 679 if (reqc != null && !Context.outerLinkExists(env, reqc, thisc)) { 680 se = new SuperExpression(where, new NullExpression(where)); 681 env.error(where, "no.default.outer.arg", reqc, getClassDefinition()); 682 } 683 if (se == null) { 684 se = new SuperExpression(where); 685 } 686 return new MethodExpression(where, se, idInit, new Expression[0]); 687 } 688 689 /** 690 * Inline the field 691 */ inline(Environment env)692 void inline(Environment env) throws ClassNotFound { 693 switch (status) { 694 case PARSED: 695 check(env); 696 inline(env); 697 break; 698 699 case CHECKED: 700 if (env.dump()) { 701 System.out.println("[inline field " + getClassDeclaration().getName() + "." + getName() + "]"); 702 } 703 status = INLINING; 704 env = new Environment(env, this); 705 706 if (isMethod()) { 707 if ((!isNative()) && (!isAbstract())) { 708 Statement s = (Statement)getValue(); 709 Context ctx = new Context((Context)null, this); 710 for (Enumeration<MemberDefinition> e = args.elements() ; e.hasMoreElements() ;) { 711 LocalMember local = (LocalMember)e.nextElement(); 712 ctx.declare(env, local); 713 } 714 setValue(s.inline(env, ctx)); 715 } 716 } else if (isInnerClass()) { 717 // some classes are checked and inlined separately 718 ClassDefinition nc = getInnerClass(); 719 if (nc instanceof SourceClass && !nc.isLocal() 720 && nc.isInsideLocal()) { 721 status = INLINING; 722 ((SourceClass)nc).inlineLocalClass(env); 723 } 724 status = INLINED; 725 break; 726 } else { 727 if (getValue() != null) { 728 Context ctx = new Context((Context)null, this); 729 if (!isStatic()) { 730 // Cf. "thisArg" in SourceClass.checkMembers(). 731 Context ctxInst = new Context(ctx, this); 732 LocalMember thisArg = 733 ((SourceClass)clazz).getThisArgument(); 734 ctxInst.declare(env, thisArg); 735 setValue(((Expression)getValue()) 736 .inlineValue(env, ctxInst)); 737 } else { 738 setValue(((Expression)getValue()) 739 .inlineValue(env, ctx)); 740 } 741 } 742 } 743 if (env.dump()) { 744 System.out.println("[inlined field " + getClassDeclaration().getName() + "." + getName() + "]"); 745 if (getValue() != null) { 746 getValue().print(System.out); 747 System.out.println(); 748 } else { 749 System.out.println("<empty>"); 750 } 751 } 752 status = INLINED; 753 break; 754 } 755 } 756 757 /** 758 * Get the value of the field (or null if the value can't be determined) 759 */ getValue(Environment env)760 public Node getValue(Environment env) throws ClassNotFound { 761 Node value = getValue(); 762 if (value != null && status != INLINED) { 763 // be sure to get the imports right: 764 env = ((SourceClass)clazz).setupEnv(env); 765 inline(env); 766 value = (status == INLINED) ? getValue() : null; 767 } 768 return value; 769 } 770 isInlineable(Environment env, boolean fromFinal)771 public boolean isInlineable(Environment env, boolean fromFinal) throws ClassNotFound { 772 if (super.isInlineable(env, fromFinal)) { 773 getValue(env); 774 return (status == INLINED) && !getClassDefinition().getError(); 775 } 776 return false; 777 } 778 779 780 /** 781 * Get the initial value of the field 782 */ getInitialValue()783 public Object getInitialValue() { 784 if (isMethod() || (getValue() == null) || (!isFinal()) || (status != INLINED)) { 785 return null; 786 } 787 return ((Expression)getValue()).getValue(); 788 } 789 790 /** 791 * Generate code 792 */ code(Environment env, Assembler asm)793 public void code(Environment env, Assembler asm) throws ClassNotFound { 794 switch (status) { 795 case PARSED: 796 check(env); 797 code(env, asm); 798 return; 799 800 case CHECKED: 801 inline(env); 802 code(env, asm); 803 return; 804 805 case INLINED: 806 // Actually generate code 807 if (env.dump()) { 808 System.out.println("[code field " + getClassDeclaration().getName() + "." + getName() + "]"); 809 } 810 if (isMethod() && (!isNative()) && (!isAbstract())) { 811 env = new Environment(env, this); 812 Context ctx = new Context((Context)null, this); 813 Statement s = (Statement)getValue(); 814 815 for (Enumeration<MemberDefinition> e = args.elements() ; e.hasMoreElements() ; ) { 816 LocalMember f = (LocalMember)e.nextElement(); 817 ctx.declare(env, f); 818 //ctx.declare(env, (LocalMember)e.nextElement()); 819 } 820 821 /* 822 if (isConstructor() && ((s == null) || (s.firstConstructor() == null))) { 823 ClassDeclaration c = getClassDefinition().getSuperClass(); 824 if (c != null) { 825 MemberDefinition field = c.getClassDefinition(env).matchMethod(env, getClassDefinition(), idInit); 826 asm.add(getWhere(), opc_aload, new Integer(0)); 827 asm.add(getWhere(), opc_invokespecial, field); 828 asm.add(getWhere(), opc_pop); 829 } 830 831 // Output initialization code 832 for (MemberDefinition f = getClassDefinition().getFirstMember() ; f != null ; f = f.getNextMember()) { 833 if (!f.isStatic()) { 834 f.codeInit(env, ctx, asm); 835 } 836 } 837 } 838 */ 839 if (s != null) { 840 s.code(env, ctx, asm); 841 } 842 if (getType().getReturnType().isType(TC_VOID) && !isInitializer()) { 843 asm.add(getWhere(), opc_return, true); 844 } 845 } 846 return; 847 } 848 } 849 codeInit(Environment env, Context ctx, Assembler asm)850 public void codeInit(Environment env, Context ctx, Assembler asm) throws ClassNotFound { 851 if (isMethod()) { 852 return; 853 } 854 switch (status) { 855 case PARSED: 856 check(env); 857 codeInit(env, ctx, asm); 858 return; 859 860 case CHECKED: 861 inline(env); 862 codeInit(env, ctx, asm); 863 return; 864 865 case INLINED: 866 // Actually generate code 867 if (env.dump()) { 868 System.out.println("[code initializer " + getClassDeclaration().getName() + "." + getName() + "]"); 869 } 870 if (getValue() != null) { 871 Expression e = (Expression)getValue(); 872 // The JLS Section 8.5 specifies that static (non-final) 873 // initializers should be executed in textual order. Eliding 874 // initializations to default values can interfere with this, 875 // so the tests for !e.equalsDefault() have been eliminated, 876 // below. 877 if (isStatic()) { 878 if (getInitialValue() == null) { 879 // removed: && !e.equalsDefault()) { 880 e.codeValue(env, ctx, asm); 881 asm.add(getWhere(), opc_putstatic, this); 882 } 883 } else { // removed: if (!e.equalsDefault()) { 884 // This code doesn't appear to be reached for 885 // instance initializers. Code for these is generated 886 // in the makeVarInits() method of the class 887 // MethodExpression. 888 asm.add(getWhere(), opc_aload, 0); 889 e.codeValue(env, ctx, asm); 890 asm.add(getWhere(), opc_putfield, this); 891 } 892 } 893 return; 894 } 895 } 896 897 /** 898 * Print for debugging 899 */ print(PrintStream out)900 public void print(PrintStream out) { 901 super.print(out); 902 if (getValue() != null) { 903 getValue().print(out); 904 out.println(); 905 } 906 } 907 } 908