History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/tools/javac/SourceMember.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/tools/javac/SourceMember.java+907−0
@@ -0,0 +1,907 @@
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
26package sun.tools.javac;
27
28import sun.tools.java.*;
29import sun.tools.tree.*;
30import sun.tools.asm.*;
31import java.util.Vector;
32import java.util.Enumeration;
33import java.util.Hashtable;
34import 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
44public
45class SourceMember extends MemberDefinition implements Constants {
46 /**
47 * The argument names (if it is a method)
48 */
49 Vector 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
67 public Vector getArguments() {
68 return args;
69 }
70
71 /**
72 * Constructor
73 * @param argNames a vector of IdentifierToken
74 */
75 public SourceMember(long where, ClassDefinition clazz,
76 String doc, int modifiers, Type type,
77 Identifier name, Vector 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
89 void createArgumentFields(Vector 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 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 &&
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 */
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 */
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 */
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 */
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) 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 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 */
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 */
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 * <tt>Vset check(Environment, Context, Vset)</tt>.
398 */
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 */
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 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 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 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 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 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
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 */
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 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 */
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
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 */
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 */
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 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
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, new Integer(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 */
900 public void print(PrintStream out) {
901 super.print(out);
902 if (getValue() != null) {
903 getValue().print(out);
904 out.println();
905 }
906 }
907}