001: /*
002: * Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.javac;
027:
028: import sun.tools.java.*;
029: import sun.tools.tree.*;
030: import sun.tools.asm.*;
031: import java.util.Vector;
032: import java.util.Enumeration;
033: import java.util.Hashtable;
034: import java.io.PrintStream;
035:
036: /**
037: * A Source Member
038: *
039: * WARNING: The contents of this source file are not part of any
040: * supported API. Code that depends on them does so at its own risk:
041: * they are subject to change or removal without notice.
042: */
043: @Deprecated
044: public class SourceMember extends MemberDefinition implements Constants {
045: /**
046: * The argument names (if it is a method)
047: */
048: Vector args;
049:
050: // set to the MemberDefinition in the interface if we have this field because
051: // it has been forced on us
052: MemberDefinition abstractSource;
053:
054: /**
055: * The status of the field
056: */
057: int status;
058:
059: static final int PARSED = 0;
060: static final int CHECKING = 1;
061: static final int CHECKED = 2;
062: static final int INLINING = 3;
063: static final int INLINED = 4;
064: static final int ERROR = 5;
065:
066: public Vector getArguments() {
067: return args;
068: }
069:
070: /**
071: * Constructor
072: * @param argNames a vector of IdentifierToken
073: */
074: public SourceMember(long where, ClassDefinition clazz, String doc,
075: int modifiers, Type type, Identifier name, Vector argNames,
076: IdentifierToken exp[], Node value) {
077: super (where, clazz, modifiers, type, name, exp, value);
078: this .documentation = doc;
079: this .args = argNames; // for the moment
080: // not until type names are resolved: createArgumentFields(argNames);
081:
082: if (ClassDefinition.containsDeprecated(documentation)) {
083: this .modifiers |= M_DEPRECATED;
084: }
085: }
086:
087: void createArgumentFields(Vector argNames) {
088: // Create a list of arguments
089: if (isMethod()) {
090: args = new Vector();
091:
092: if (isConstructor() || !(isStatic() || isInitializer())) {
093: args
094: .addElement(((SourceClass) clazz)
095: .getThisArgument());
096: }
097:
098: if (argNames != null) {
099: Enumeration 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:
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:
176: void addOuterThis() {
177: UplevelReference refs = clazz.getReferences();
178:
179: // See if we have a client outer field.
180: while (refs != null && !refs.isClientOuterField()) {
181: refs = refs.getNext();
182: }
183:
184: // There is no outer this argument. Quit.
185: if (refs == null) {
186: return;
187: }
188:
189: // Get the old arg types.
190: Type oldArgTypes[] = type.getArgumentTypes();
191:
192: // And make an array for the new ones with space for one more.
193: Type argTypes[] = new Type[oldArgTypes.length + 1];
194:
195: LocalMember arg = refs.getLocalArgument();
196: outerThisArg = arg;
197:
198: // args is our list of arguments. It contains a `this', so
199: // we insert at position 1. The list of types does not have a
200: // this, so we insert at position 0.
201: args.insertElementAt(arg, 1);
202: argTypes[0] = arg.getType();
203:
204: // Add on the rest of the constructor arguments.
205: for (int i = 0; i < oldArgTypes.length; i++) {
206: argTypes[i + 1] = oldArgTypes[i];
207: }
208:
209: type = Type.tMethod(type.getReturnType(), argTypes);
210: }
211:
212: /**
213: * Prepend argument names and argument types for local variable references.
214: * This information is never seen by the type-check phase,
215: * but it affects code generation, which is the earliest moment
216: * we have comprehensive information on uplevel references.
217: * The code() methods tweaks the constructor calls, prepending
218: * the proper values to the argument list.
219: */
220: void addUplevelArguments() {
221: UplevelReference refs = clazz.getReferences();
222: clazz.getReferencesFrozen();
223:
224: // Count how many uplevels we have to add.
225: int count = 0;
226: for (UplevelReference r = refs; r != null; r = r.getNext()) {
227: if (!r.isClientOuterField()) {
228: count += 1;
229: }
230: }
231:
232: if (count == 0) {
233: // None to add, quit.
234: return;
235: }
236:
237: // Get the old argument types.
238: Type oldArgTypes[] = type.getArgumentTypes();
239:
240: // Make an array with enough room for the new.
241: Type argTypes[] = new Type[oldArgTypes.length + count];
242:
243: // Add all of the late uplevel references to args and argTypes.
244: // Note that they are `off-by-one' because of the `this'.
245: int ins = 0;
246: for (UplevelReference r = refs; r != null; r = r.getNext()) {
247: if (!r.isClientOuterField()) {
248: LocalMember arg = r.getLocalArgument();
249:
250: args.insertElementAt(arg, 1 + ins);
251: argTypes[ins] = arg.getType();
252:
253: ins++;
254: }
255: }
256:
257: // Add the rest of the old arguments.
258: for (int i = 0; i < oldArgTypes.length; i++) {
259: argTypes[ins + i] = oldArgTypes[i];
260: }
261:
262: type = Type.tMethod(type.getReturnType(), argTypes);
263: }
264:
265: /**
266: * Constructor for an inner class.
267: */
268: public SourceMember(ClassDefinition innerClass) {
269: super (innerClass);
270: }
271:
272: /**
273: * Constructor.
274: * Used only to generate an abstract copy of a method that a class
275: * inherits from an interface
276: */
277: public SourceMember(MemberDefinition f, ClassDefinition c,
278: Environment env) {
279: this (f.getWhere(), c, f.getDocumentation(), f.getModifiers()
280: | M_ABSTRACT, f.getType(), f.getName(), null, f
281: .getExceptionIds(), null);
282: this .args = f.getArguments();
283: this .abstractSource = f;
284: this .exp = f.getExceptions(env);
285: }
286:
287: /**
288: * Get exceptions
289: */
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: */
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:
324: public void resolveTypeStructure(Environment env) {
325: if (tracing)
326: env.dtEnter("SourceMember.resolveTypeStructure: " + this );
327:
328: // A member should only be resolved once. For a constructor, it is imperative
329: // that 'addOuterThis' be called only once, else the outer instance argument may
330: // be inserted into the argument list multiple times.
331:
332: if (resolved) {
333: if (tracing)
334: env.dtEvent("SourceMember.resolveTypeStructure: OK "
335: + this );
336: // This case shouldn't be happening. It is the responsibility
337: // of our callers to avoid attempting multiple resolutions of a member.
338: // *** REMOVE FOR SHIPMENT? ***
339: throw new CompilerError("multiple member type resolution");
340: //return;
341: } else {
342: if (tracing)
343: env
344: .dtEvent("SourceMember.resolveTypeStructure: RESOLVING "
345: + this );
346: resolved = true;
347: }
348:
349: super .resolveTypeStructure(env);
350: if (isInnerClass()) {
351: ClassDefinition nc = getInnerClass();
352: if (nc instanceof SourceClass && !nc.isLocal()) {
353: ((SourceClass) nc).resolveTypeStructure(env);
354: }
355: type = innerClass.getType();
356: } else {
357: // Expand all class names in 'type', including those that are not
358: // fully-qualified or refer to inner classes, into fully-qualified
359: // names. Local and anonymous classes get synthesized names here,
360: // corresponding to the class files that will be generated. This is
361: // currently the only place where 'resolveNames' is used.
362: type = env.resolveNames(getClassDefinition(), type,
363: isSynthetic());
364:
365: // do the throws also:
366: getExceptions(env);
367:
368: if (isMethod()) {
369: Vector argNames = args;
370: args = null;
371: createArgumentFields(argNames);
372: // Add outer instance argument for constructors.
373: if (isConstructor()) {
374: addOuterThis();
375: }
376: }
377: }
378: if (tracing)
379: env.dtExit("SourceMember.resolveTypeStructure: " + this );
380: }
381:
382: /**
383: * Get the class declaration in which the field is actually defined
384: */
385: public ClassDeclaration getDefiningClassDeclaration() {
386: if (abstractSource == null)
387: return super .getDefiningClassDeclaration();
388: else
389: return abstractSource.getDefiningClassDeclaration();
390: }
391:
392: /**
393: * A source field never reports deprecation, since the compiler
394: * allows access to deprecated features that are being compiled
395: * in the same job.
396: */
397: public boolean reportDeprecated(Environment env) {
398: return false;
399: }
400:
401: /**
402: * Check this field.
403: * <p>
404: * This is the method which requests checking.
405: * The real work is done by
406: * <tt>Vset check(Environment, Context, Vset)</tt>.
407: */
408: public void check(Environment env) throws ClassNotFound {
409: if (tracing)
410: env.dtEnter("SourceMember.check: " + getName()
411: + ", status = " + status);
412: // rely on the class to check all fields in the proper order
413: if (status == PARSED) {
414: if (isSynthetic() && getValue() == null) {
415: // break a big cycle for small synthetic variables
416: status = CHECKED;
417: if (tracing)
418: env.dtExit("SourceMember.check: BREAKING CYCLE");
419: return;
420: }
421: if (tracing)
422: env.dtEvent("SourceMember.check: CHECKING CLASS");
423: clazz.check(env);
424: if (status == PARSED) {
425: if (getClassDefinition().getError()) {
426: status = ERROR;
427: } else {
428: if (tracing)
429: env.dtExit("SourceMember.check: CHECK FAILED");
430: throw new CompilerError("check failed");
431: }
432: }
433: }
434: if (tracing)
435: env.dtExit("SourceMember.check: DONE " + getName()
436: + ", status = " + status);
437: }
438:
439: /**
440: * Check a field.
441: * @param vset tells which uplevel variables are definitely assigned
442: * The vset is also used to track the initialization of blank finals
443: * by whichever fields which are relevant to them.
444: */
445: public Vset check(Environment env, Context ctx, Vset vset)
446: throws ClassNotFound {
447: if (tracing)
448: env.dtEvent("SourceMember.check: MEMBER " + getName()
449: + ", status = " + status);
450: if (status == PARSED) {
451: if (isInnerClass()) {
452: // some classes are checked separately
453: ClassDefinition nc = getInnerClass();
454: if (nc instanceof SourceClass && !nc.isLocal()
455: && nc.isInsideLocal()) {
456: status = CHECKING;
457: vset = ((SourceClass) nc).checkInsideClass(env,
458: ctx, vset);
459: }
460: status = CHECKED;
461: return vset;
462: }
463: if (env.dump()) {
464: System.out.println("[check field "
465: + getClassDeclaration().getName() + "."
466: + getName() + "]");
467: if (getValue() != null) {
468: getValue().print(System.out);
469: System.out.println();
470: }
471: }
472: env = new Environment(env, this );
473:
474: // This is where all checking of names appearing within the type
475: // of the member is done. Includes return type and argument types.
476: // Since only one location ('where') for error messages is provided,
477: // localization of errors is poor. Throws clauses are handled below.
478: env.resolve(where, getClassDefinition(), getType());
479:
480: // Make sure that all the classes that we claim to throw really
481: // are subclasses of Throwable, and are classes that we can reach
482: if (isMethod()) {
483: ClassDeclaration throwable = env
484: .getClassDeclaration(idJavaLangThrowable);
485: ClassDeclaration exp[] = getExceptions(env);
486: for (int i = 0; i < exp.length; i++) {
487: ClassDefinition def;
488: long where = getWhere();
489: if (expIds != null && i < expIds.length) {
490: where = IdentifierToken.getWhere(expIds[i],
491: where);
492: }
493: try {
494: def = exp[i].getClassDefinition(env);
495:
496: // Validate access for all inner-class components
497: // of a qualified name, not just the last one, which
498: // is checked below. Yes, this is a dirty hack...
499: // Part of fix for 4094658.
500: env.resolveByName(where, getClassDefinition(),
501: def.getName());
502:
503: } catch (ClassNotFound e) {
504: env.error(where, "class.not.found", e.name,
505: "throws");
506: break;
507: }
508: def.noteUsedBy(getClassDefinition(), where, env);
509: if (!getClassDefinition().canAccess(env,
510: def.getClassDeclaration())) {
511: env.error(where, "cant.access.class", def);
512: } else if (!def.subClassOf(env, throwable)) {
513: env.error(where, "throws.not.throwable", def);
514: }
515: }
516: }
517:
518: status = CHECKING;
519:
520: if (isMethod() && args != null) {
521: int length = args.size();
522: outer_loop: for (int i = 0; i < length; i++) {
523: LocalMember lf = (LocalMember) (args.elementAt(i));
524: Identifier name_i = lf.getName();
525: for (int j = i + 1; j < length; j++) {
526: LocalMember lf2 = (LocalMember) (args
527: .elementAt(j));
528: Identifier name_j = lf2.getName();
529: if (name_i.equals(name_j)) {
530: env.error(lf2.getWhere(),
531: "duplicate.argument", name_i);
532: break outer_loop;
533: }
534: }
535: }
536: }
537:
538: if (getValue() != null) {
539: ctx = new Context(ctx, this );
540:
541: if (isMethod()) {
542: Statement s = (Statement) getValue();
543: // initialize vset, indication that each of the arguments
544: // to the function has a value
545:
546: for (Enumeration e = args.elements(); e
547: .hasMoreElements();) {
548: LocalMember f = (LocalMember) e.nextElement();
549: vset.addVar(ctx.declare(env, f));
550: }
551:
552: if (isConstructor()) {
553: // Undefine "this" in some constructors, until after
554: // the super constructor has been called.
555: vset.clearVar(ctx.getThisNumber());
556:
557: // If the first thing in the definition isn't a call
558: // to either super() or this(), then insert one.
559: Expression supCall = s.firstConstructor();
560: if ((supCall == null)
561: && (getClassDefinition()
562: .getSuperClass() != null)) {
563: supCall = getDefaultSuperCall(env);
564: Statement scs = new ExpressionStatement(
565: where, supCall);
566: s = Statement.insertStatement(scs, s);
567: setValue(s);
568: }
569: }
570:
571: //System.out.println("VSET = " + vset);
572: ClassDeclaration exp[] = getExceptions(env);
573: int htsize = (exp.length > 3) ? 17 : 7;
574: Hashtable thrown = new Hashtable(htsize);
575:
576: vset = s.checkMethod(env, ctx, vset, thrown);
577:
578: ClassDeclaration ignore1 = env
579: .getClassDeclaration(idJavaLangError);
580: ClassDeclaration ignore2 = env
581: .getClassDeclaration(idJavaLangRuntimeException);
582:
583: for (Enumeration e = thrown.keys(); e
584: .hasMoreElements();) {
585: ClassDeclaration c = (ClassDeclaration) e
586: .nextElement();
587: ClassDefinition def = c.getClassDefinition(env);
588: if (def.subClassOf(env, ignore1)
589: || def.subClassOf(env, ignore2)) {
590: continue;
591: }
592:
593: boolean ok = false;
594: if (!isInitializer()) {
595: for (int i = 0; i < exp.length; i++) {
596: if (def.subClassOf(env, exp[i])) {
597: ok = true;
598: }
599: }
600: }
601: if (!ok) {
602: Node n = (Node) thrown.get(c);
603: long where = n.getWhere();
604: String errorMsg;
605:
606: if (isConstructor()) {
607: if (where == getClassDefinition()
608: .getWhere()) {
609:
610: // If this message is being generated for
611: // a default constructor, we should give
612: // a different error message. Currently
613: // we check for this by seeing if the
614: // constructor has the same "where" as
615: // its class. This is a bit kludgy, but
616: // works. (bug id 4034836)
617: errorMsg = "def.constructor.exception";
618: } else {
619: // Constructor with uncaught exception.
620: errorMsg = "constructor.exception";
621: }
622: } else if (isInitializer()) {
623: // Initializer with uncaught exception.
624: errorMsg = "initializer.exception";
625: } else {
626: // Method with uncaught exception.
627: errorMsg = "uncaught.exception";
628: }
629: env.error(where, errorMsg, c.getName());
630: }
631: }
632: } else {
633: Hashtable thrown = new Hashtable(3); // small & throw-away
634: Expression val = (Expression) getValue();
635:
636: vset = val.checkInitializer(env, ctx, vset,
637: getType(), thrown);
638: setValue(val.convert(env, ctx, getType(), val));
639:
640: // Complain about static final members of inner classes that
641: // do not have an initializer that is a constant expression.
642: // In general, static members are not permitted for inner
643: // classes, but an exception is made for named constants.
644: // Other cases of static members, including non-final ones,
645: // are handled in 'SourceClass'. Part of fix for 4095568.
646: if (isStatic() && isFinal() && !clazz.isTopLevel()) {
647: if (!((Expression) getValue()).isConstant()) {
648: env.error(where, "static.inner.field",
649: getName(), this );
650: setValue(null);
651: }
652: }
653:
654: // Both RuntimeExceptions and Errors should be
655: // allowed in initializers. Fix for bug 4102541.
656: ClassDeclaration except = env
657: .getClassDeclaration(idJavaLangThrowable);
658: ClassDeclaration ignore1 = env
659: .getClassDeclaration(idJavaLangError);
660: ClassDeclaration ignore2 = env
661: .getClassDeclaration(idJavaLangRuntimeException);
662:
663: for (Enumeration e = thrown.keys(); e
664: .hasMoreElements();) {
665: ClassDeclaration c = (ClassDeclaration) e
666: .nextElement();
667: ClassDefinition def = c.getClassDefinition(env);
668:
669: if (!def.subClassOf(env, ignore1)
670: && !def.subClassOf(env, ignore2)
671: && def.subClassOf(env, except)) {
672: Node n = (Node) thrown.get(c);
673: env.error(n.getWhere(),
674: "initializer.exception", c
675: .getName());
676: }
677: }
678: }
679: if (env.dump()) {
680: getValue().print(System.out);
681: System.out.println();
682: }
683: }
684: status = getClassDefinition().getError() ? ERROR : CHECKED;
685: }
686:
687: // Initializers (static and instance) must be able to complete normally.
688: if (isInitializer() && vset.isDeadEnd()) {
689: env.error(where, "init.no.normal.completion");
690: vset = vset.clearDeadEnd();
691: }
692:
693: return vset;
694: }
695:
696: // helper to check(): synthesize a missing super() call
697: private Expression getDefaultSuperCall(Environment env) {
698: Expression se = null;
699: ClassDefinition sclass = getClassDefinition().getSuperClass()
700: .getClassDefinition();
701: // does the superclass constructor require an enclosing instance?
702: ClassDefinition reqc = (sclass == null) ? null : sclass
703: .isTopLevel() ? null : sclass.getOuterClass();
704: ClassDefinition this c = getClassDefinition();
705: if (reqc != null && !Context.outerLinkExists(env, reqc, this c)) {
706: se = new SuperExpression(where, new NullExpression(where));
707: env.error(where, "no.default.outer.arg", reqc,
708: getClassDefinition());
709: }
710: if (se == null) {
711: se = new SuperExpression(where);
712: }
713: return new MethodExpression(where, se, idInit,
714: new Expression[0]);
715: }
716:
717: /**
718: * Inline the field
719: */
720: void inline(Environment env) throws ClassNotFound {
721: switch (status) {
722: case PARSED:
723: check(env);
724: inline(env);
725: break;
726:
727: case CHECKED:
728: if (env.dump()) {
729: System.out.println("[inline field "
730: + getClassDeclaration().getName() + "."
731: + getName() + "]");
732: }
733: status = INLINING;
734: env = new Environment(env, this );
735:
736: if (isMethod()) {
737: if ((!isNative()) && (!isAbstract())) {
738: Statement s = (Statement) getValue();
739: Context ctx = new Context((Context) null, this );
740: for (Enumeration e = args.elements(); e
741: .hasMoreElements();) {
742: LocalMember local = (LocalMember) e
743: .nextElement();
744: ctx.declare(env, local);
745: }
746: setValue(s.inline(env, ctx));
747: }
748: } else if (isInnerClass()) {
749: // some classes are checked and inlined separately
750: ClassDefinition nc = getInnerClass();
751: if (nc instanceof SourceClass && !nc.isLocal()
752: && nc.isInsideLocal()) {
753: status = INLINING;
754: ((SourceClass) nc).inlineLocalClass(env);
755: }
756: status = INLINED;
757: break;
758: } else {
759: if (getValue() != null) {
760: Context ctx = new Context((Context) null, this );
761: if (!isStatic()) {
762: // Cf. "thisArg" in SourceClass.checkMembers().
763: Context ctxInst = new Context(ctx, this );
764: LocalMember this Arg = ((SourceClass) clazz)
765: .getThisArgument();
766: ctxInst.declare(env, this Arg);
767: setValue(((Expression) getValue()).inlineValue(
768: env, ctxInst));
769: } else {
770: setValue(((Expression) getValue()).inlineValue(
771: env, ctx));
772: }
773: }
774: }
775: if (env.dump()) {
776: System.out.println("[inlined field "
777: + getClassDeclaration().getName() + "."
778: + getName() + "]");
779: if (getValue() != null) {
780: getValue().print(System.out);
781: System.out.println();
782: } else {
783: System.out.println("<empty>");
784: }
785: }
786: status = INLINED;
787: break;
788: }
789: }
790:
791: /**
792: * Get the value of the field (or null if the value can't be determined)
793: */
794: public Node getValue(Environment env) throws ClassNotFound {
795: Node value = getValue();
796: if (value != null && status != INLINED) {
797: // be sure to get the imports right:
798: env = ((SourceClass) clazz).setupEnv(env);
799: inline(env);
800: value = (status == INLINED) ? getValue() : null;
801: }
802: return value;
803: }
804:
805: public boolean isInlineable(Environment env, boolean fromFinal)
806: throws ClassNotFound {
807: if (super .isInlineable(env, fromFinal)) {
808: getValue(env);
809: return (status == INLINED)
810: && !getClassDefinition().getError();
811: }
812: return false;
813: }
814:
815: /**
816: * Get the initial value of the field
817: */
818: public Object getInitialValue() {
819: if (isMethod() || (getValue() == null) || (!isFinal())
820: || (status != INLINED)) {
821: return null;
822: }
823: return ((Expression) getValue()).getValue();
824: }
825:
826: /**
827: * Generate code
828: */
829: public void code(Environment env, Assembler asm)
830: throws ClassNotFound {
831: switch (status) {
832: case PARSED:
833: check(env);
834: code(env, asm);
835: return;
836:
837: case CHECKED:
838: inline(env);
839: code(env, asm);
840: return;
841:
842: case INLINED:
843: // Actually generate code
844: if (env.dump()) {
845: System.out.println("[code field "
846: + getClassDeclaration().getName() + "."
847: + getName() + "]");
848: }
849: if (isMethod() && (!isNative()) && (!isAbstract())) {
850: env = new Environment(env, this );
851: Context ctx = new Context((Context) null, this );
852: Statement s = (Statement) getValue();
853:
854: for (Enumeration e = args.elements(); e
855: .hasMoreElements();) {
856: LocalMember f = (LocalMember) e.nextElement();
857: ctx.declare(env, f);
858: //ctx.declare(env, (LocalMember)e.nextElement());
859: }
860:
861: /*
862: if (isConstructor() && ((s == null) || (s.firstConstructor() == null))) {
863: ClassDeclaration c = getClassDefinition().getSuperClass();
864: if (c != null) {
865: MemberDefinition field = c.getClassDefinition(env).matchMethod(env, getClassDefinition(), idInit);
866: asm.add(getWhere(), opc_aload, new Integer(0));
867: asm.add(getWhere(), opc_invokespecial, field);
868: asm.add(getWhere(), opc_pop);
869: }
870:
871: // Output initialization code
872: for (MemberDefinition f = getClassDefinition().getFirstMember() ; f != null ; f = f.getNextMember()) {
873: if (!f.isStatic()) {
874: f.codeInit(env, ctx, asm);
875: }
876: }
877: }
878: */
879: if (s != null) {
880: s.code(env, ctx, asm);
881: }
882: if (getType().getReturnType().isType(TC_VOID)
883: && !isInitializer()) {
884: asm.add(getWhere(), opc_return, true);
885: }
886: }
887: return;
888: }
889: }
890:
891: public void codeInit(Environment env, Context ctx, Assembler asm)
892: throws ClassNotFound {
893: if (isMethod()) {
894: return;
895: }
896: switch (status) {
897: case PARSED:
898: check(env);
899: codeInit(env, ctx, asm);
900: return;
901:
902: case CHECKED:
903: inline(env);
904: codeInit(env, ctx, asm);
905: return;
906:
907: case INLINED:
908: // Actually generate code
909: if (env.dump()) {
910: System.out.println("[code initializer "
911: + getClassDeclaration().getName() + "."
912: + getName() + "]");
913: }
914: if (getValue() != null) {
915: Expression e = (Expression) getValue();
916: // The JLS Section 8.5 specifies that static (non-final)
917: // initializers should be executed in textual order. Eliding
918: // initializations to default values can interfere with this,
919: // so the tests for !e.equalsDefault() have been eliminated,
920: // below.
921: if (isStatic()) {
922: if (getInitialValue() == null) {
923: // removed: && !e.equalsDefault()) {
924: e.codeValue(env, ctx, asm);
925: asm.add(getWhere(), opc_putstatic, this );
926: }
927: } else { // removed: if (!e.equalsDefault()) {
928: // This code doesn't appear to be reached for
929: // instance initializers. Code for these is generated
930: // in the makeVarInits() method of the class
931: // MethodExpression.
932: asm.add(getWhere(), opc_aload, new Integer(0));
933: e.codeValue(env, ctx, asm);
934: asm.add(getWhere(), opc_putfield, this );
935: }
936: }
937: return;
938: }
939: }
940:
941: /**
942: * Print for debugging
943: */
944: public void print(PrintStream out) {
945: super.print(out);
946: if (getValue() != null) {
947: getValue().print(out);
948: out.println();
949: }
950: }
951: }
|