/*
* Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.javac;
import sun.tools.java.*;
import sun.tools.tree.*;
import sun.tools.asm.*;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Hashtable;
import java.io.PrintStream;
A Source Member
WARNING: The contents of this source file are not part of any
supported API. Code that depends on them does so at its own risk:
they are subject to change or removal without notice.
/**
* A Source Member
*
* WARNING: The contents of this source file are not part of any
* supported API. Code that depends on them does so at its own risk:
* they are subject to change or removal without notice.
*/
@Deprecated
public
class SourceMember extends MemberDefinition implements Constants {
The argument names (if it is a method)
/**
* The argument names (if it is a method)
*/
Vector args;
// set to the MemberDefinition in the interface if we have this field because
// it has been forced on us
MemberDefinition abstractSource;
The status of the field
/**
* The status of the field
*/
int status;
static final int PARSED = 0;
static final int CHECKING = 1;
static final int CHECKED = 2;
static final int INLINING = 3;
static final int INLINED = 4;
static final int ERROR = 5;
public Vector getArguments() {
return args;
}
Constructor
Params: - argNames – a vector of IdentifierToken
/**
* Constructor
* @param argNames a vector of IdentifierToken
*/
public SourceMember(long where, ClassDefinition clazz,
String doc, int modifiers, Type type,
Identifier name, Vector argNames,
IdentifierToken exp[], Node value) {
super(where, clazz, modifiers, type, name, exp, value);
this.documentation = doc;
this.args = argNames; // for the moment
// not until type names are resolved: createArgumentFields(argNames);
if (ClassDefinition.containsDeprecated(documentation)) {
this.modifiers |= M_DEPRECATED;
}
}
void createArgumentFields(Vector argNames) {
// Create a list of arguments
if (isMethod()) {
args = new Vector();
if (isConstructor() || !(isStatic() || isInitializer())) {
args.addElement(((SourceClass)clazz).getThisArgument());
}
if (argNames != null) {
Enumeration e = argNames.elements();
Type argTypes[] = getType().getArgumentTypes();
for (int i = 0 ; i < argTypes.length ; i++) {
Object x = e.nextElement();
if (x instanceof LocalMember) {
// This should not happen, but it does
// in cases of vicious cyclic inheritance.
args = argNames;
return;
}
Identifier id;
int mod;
long where;
if (x instanceof Identifier) {
// allow argNames to be simple Identifiers (deprecated!)
id = (Identifier)x;
mod = 0;
where = getWhere();
} else {
IdentifierToken token = (IdentifierToken)x;
id = token.getName();
mod = token.getModifiers();
where = token.getWhere();
}
args.addElement(new LocalMember(where, clazz, mod,
argTypes[i], id));
}
}
}
}
// The methods addOuterThis() and addUplevelArguments() were
// both originally part of a single method called addUplevelArguments()
// which took a single boolean parameter describing which of the
// two behaviors it wanted.
//
// The original addUplevelArguments() claimed to keep the arguments in
// the following order:
//
// (1) <this> <early outer this> <uplevel arguments...> <true arguments...>
//
// (By <early outer this> I am referring to the clientOuterField added
// to some constructors when they are created. If an outer this is
// added later, on demand, then this is mixed in with the rest of the
// uplevel arguments and is added by addUplevelArguments.)
//
// In reality, the `args' Vector was generated in this order, but the
// Type array `argTypes' was generated as:
//
// (2) <this> <uplevel arguments...> <early outer this> <true arguments...>
//
// This didn't make a difference in the common case -- that is, when
// a class had an <outer.this> or <uplevel arguments...> but not both.
// Both can happen in the case that a member class is declared inside
// of a local class. It seems that the calling sequences, generated
// in places like NewInstanceExpression.codeCommon(), use order (2),
// so I have changed the code below to stick with that order. Since
// the only time this happens is in classes which are insideLocal, no
// one should be able to tell the difference between these orders.
// (bug number 4085633)
LocalMember outerThisArg = null;
Get outer instance link, or null if none.
/**
* Get outer instance link, or null if none.
*/
public LocalMember getOuterThisArg() {
return outerThisArg;
}
Add the outer.this argument to the list of arguments for this
constructor. This is called from resolveTypeStructure. Any
additional uplevel arguments get added later by addUplevelArguments().
/**
* Add the outer.this argument to the list of arguments for this
* constructor. This is called from resolveTypeStructure. Any
* additional uplevel arguments get added later by addUplevelArguments().
*/
void addOuterThis() {
UplevelReference refs = clazz.getReferences();
// See if we have a client outer field.
while (refs != null &&
!refs.isClientOuterField()) {
refs = refs.getNext();
}
// There is no outer this argument. Quit.
if (refs == null) {
return;
}
// Get the old arg types.
Type oldArgTypes[] = type.getArgumentTypes();
// And make an array for the new ones with space for one more.
Type argTypes[] = new Type[oldArgTypes.length + 1];
LocalMember arg = refs.getLocalArgument();
outerThisArg = arg;
// args is our list of arguments. It contains a `this', so
// we insert at position 1. The list of types does not have a
// this, so we insert at position 0.
args.insertElementAt(arg, 1);
argTypes[0] = arg.getType();
// Add on the rest of the constructor arguments.
for (int i = 0; i < oldArgTypes.length; i++) {
argTypes[i + 1] = oldArgTypes[i];
}
type = Type.tMethod(type.getReturnType(), argTypes);
}
Prepend argument names and argument types for local variable references.
This information is never seen by the type-check phase,
but it affects code generation, which is the earliest moment
we have comprehensive information on uplevel references.
The code() methods tweaks the constructor calls, prepending
the proper values to the argument list.
/**
* Prepend argument names and argument types for local variable references.
* This information is never seen by the type-check phase,
* but it affects code generation, which is the earliest moment
* we have comprehensive information on uplevel references.
* The code() methods tweaks the constructor calls, prepending
* the proper values to the argument list.
*/
void addUplevelArguments() {
UplevelReference refs = clazz.getReferences();
clazz.getReferencesFrozen();
// Count how many uplevels we have to add.
int count = 0;
for (UplevelReference r = refs; r != null; r = r.getNext()) {
if (!r.isClientOuterField()) {
count += 1;
}
}
if (count == 0) {
// None to add, quit.
return;
}
// Get the old argument types.
Type oldArgTypes[] = type.getArgumentTypes();
// Make an array with enough room for the new.
Type argTypes[] = new Type[oldArgTypes.length + count];
// Add all of the late uplevel references to args and argTypes.
// Note that they are `off-by-one' because of the `this'.
int ins = 0;
for (UplevelReference r = refs; r != null; r = r.getNext()) {
if (!r.isClientOuterField()) {
LocalMember arg = r.getLocalArgument();
args.insertElementAt(arg, 1 + ins);
argTypes[ins] = arg.getType();
ins++;
}
}
// Add the rest of the old arguments.
for (int i = 0; i < oldArgTypes.length; i++) {
argTypes[ins + i] = oldArgTypes[i];
}
type = Type.tMethod(type.getReturnType(), argTypes);
}
Constructor for an inner class.
/**
* Constructor for an inner class.
*/
public SourceMember(ClassDefinition innerClass) {
super(innerClass);
}
Constructor.
Used only to generate an abstract copy of a method that a class
inherits from an interface
/**
* Constructor.
* Used only to generate an abstract copy of a method that a class
* inherits from an interface
*/
public SourceMember(MemberDefinition f, ClassDefinition c, Environment env) {
this(f.getWhere(), c, f.getDocumentation(),
f.getModifiers() | M_ABSTRACT, f.getType(), f.getName(), null,
f.getExceptionIds(), null);
this.args = f.getArguments();
this.abstractSource = f;
this.exp = f.getExceptions(env);
}
Get exceptions
/**
* Get exceptions
*/
public ClassDeclaration[] getExceptions(Environment env) {
if ((!isMethod()) || (exp != null)) {
return exp;
}
if (expIds == null) {
// (should not happen)
exp = new ClassDeclaration[0];
return exp;
}
// be sure to get the imports right:
env = ((SourceClass)getClassDefinition()).setupEnv(env);
exp = new ClassDeclaration[expIds.length];
for (int i = 0; i < exp.length; i++) {
Identifier e = expIds[i].getName();
Identifier rexp = getClassDefinition().resolveName(env, e);
exp[i] = env.getClassDeclaration(rexp);
}
return exp;
}
Set array of name-resolved exceptions directly, e.g., for access methods.
/**
* Set array of name-resolved exceptions directly, e.g., for access methods.
*/
public void setExceptions(ClassDeclaration[] exp) {
this.exp = exp;
}
Resolve types in a field, after parsing.
See Also: - resolveTypeStructure
/**
* Resolve types in a field, after parsing.
* @see ClassDefinition.resolveTypeStructure
*/
public boolean resolved = false;
public void resolveTypeStructure(Environment env) {
if (tracing) env.dtEnter("SourceMember.resolveTypeStructure: " + this);
// A member should only be resolved once. For a constructor, it is imperative
// that 'addOuterThis' be called only once, else the outer instance argument may
// be inserted into the argument list multiple times.
if (resolved) {
if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: OK " + this);
// This case shouldn't be happening. It is the responsibility
// of our callers to avoid attempting multiple resolutions of a member.
// *** REMOVE FOR SHIPMENT? ***
throw new CompilerError("multiple member type resolution");
//return;
} else {
if (tracing) env.dtEvent("SourceMember.resolveTypeStructure: RESOLVING " + this);
resolved = true;
}
super.resolveTypeStructure(env);
if (isInnerClass()) {
ClassDefinition nc = getInnerClass();
if (nc instanceof SourceClass && !nc.isLocal()) {
((SourceClass)nc).resolveTypeStructure(env);
}
type = innerClass.getType();
} else {
// Expand all class names in 'type', including those that are not
// fully-qualified or refer to inner classes, into fully-qualified
// names. Local and anonymous classes get synthesized names here,
// corresponding to the class files that will be generated. This is
// currently the only place where 'resolveNames' is used.
type = env.resolveNames(getClassDefinition(), type, isSynthetic());
// do the throws also:
getExceptions(env);
if (isMethod()) {
Vector argNames = args; args = null;
createArgumentFields(argNames);
// Add outer instance argument for constructors.
if (isConstructor()) {
addOuterThis();
}
}
}
if (tracing) env.dtExit("SourceMember.resolveTypeStructure: " + this);
}
Get the class declaration in which the field is actually defined
/**
* Get the class declaration in which the field is actually defined
*/
public ClassDeclaration getDefiningClassDeclaration() {
if (abstractSource == null)
return super.getDefiningClassDeclaration();
else
return abstractSource.getDefiningClassDeclaration();
}
A source field never reports deprecation, since the compiler
allows access to deprecated features that are being compiled
in the same job.
/**
* A source field never reports deprecation, since the compiler
* allows access to deprecated features that are being compiled
* in the same job.
*/
public boolean reportDeprecated(Environment env) {
return false;
}
Check this field.
This is the method which requests checking.
The real work is done by
Vset check(Environment, Context, Vset).
/**
* Check this field.
* <p>
* This is the method which requests checking.
* The real work is done by
* <tt>Vset check(Environment, Context, Vset)</tt>.
*/
public void check(Environment env) throws ClassNotFound {
if (tracing) env.dtEnter("SourceMember.check: " +
getName() + ", status = " + status);
// rely on the class to check all fields in the proper order
if (status == PARSED) {
if (isSynthetic() && getValue() == null) {
// break a big cycle for small synthetic variables
status = CHECKED;
if (tracing)
env.dtExit("SourceMember.check: BREAKING CYCLE");
return;
}
if (tracing) env.dtEvent("SourceMember.check: CHECKING CLASS");
clazz.check(env);
if (status == PARSED) {
if (getClassDefinition().getError()) {
status = ERROR;
} else {
if (tracing)
env.dtExit("SourceMember.check: CHECK FAILED");
throw new CompilerError("check failed");
}
}
}
if (tracing) env.dtExit("SourceMember.check: DONE " +
getName() + ", status = " + status);
}
Check a field.
Params: - vset – tells which uplevel variables are definitely assigned
The vset is also used to track the initialization of blank finals
by whichever fields which are relevant to them.
/**
* Check a field.
* @param vset tells which uplevel variables are definitely assigned
* The vset is also used to track the initialization of blank finals
* by whichever fields which are relevant to them.
*/
public Vset check(Environment env, Context ctx, Vset vset) throws ClassNotFound {
if (tracing) env.dtEvent("SourceMember.check: MEMBER " +
getName() + ", status = " + status);
if (status == PARSED) {
if (isInnerClass()) {
// some classes are checked separately
ClassDefinition nc = getInnerClass();
if (nc instanceof SourceClass && !nc.isLocal()
&& nc.isInsideLocal()) {
status = CHECKING;
vset = ((SourceClass)nc).checkInsideClass(env, ctx, vset);
}
status = CHECKED;
return vset;
}
if (env.dump()) {
System.out.println("[check field " + getClassDeclaration().getName() + "." + getName() + "]");
if (getValue() != null) {
getValue().print(System.out);
System.out.println();
}
}
env = new Environment(env, this);
// This is where all checking of names appearing within the type
// of the member is done. Includes return type and argument types.
// Since only one location ('where') for error messages is provided,
// localization of errors is poor. Throws clauses are handled below.
env.resolve(where, getClassDefinition(), getType());
// Make sure that all the classes that we claim to throw really
// are subclasses of Throwable, and are classes that we can reach
if (isMethod()) {
ClassDeclaration throwable =
env.getClassDeclaration(idJavaLangThrowable);
ClassDeclaration exp[] = getExceptions(env);
for (int i = 0 ; i < exp.length ; i++) {
ClassDefinition def;
long where = getWhere();
if (expIds != null && i < expIds.length) {
where = IdentifierToken.getWhere(expIds[i], where);
}
try {
def = exp[i].getClassDefinition(env);
// Validate access for all inner-class components
// of a qualified name, not just the last one, which
// is checked below. Yes, this is a dirty hack...
// Part of fix for 4094658.
env.resolveByName(where, getClassDefinition(), def.getName());
} catch (ClassNotFound e) {
env.error(where, "class.not.found", e.name, "throws");
break;
}
def.noteUsedBy(getClassDefinition(), where, env);
if (!getClassDefinition().
canAccess(env, def.getClassDeclaration())) {
env.error(where, "cant.access.class", def);
} else if (!def.subClassOf(env, throwable)) {
env.error(where, "throws.not.throwable", def);
}
}
}
status = CHECKING;
if (isMethod() && args != null) {
int length = args.size();
outer_loop:
for (int i = 0; i < length; i++) {
LocalMember lf = (LocalMember)(args.elementAt(i));
Identifier name_i = lf.getName();
for (int j = i + 1; j < length; j++) {
LocalMember lf2 = (LocalMember)(args.elementAt(j));
Identifier name_j = lf2.getName();
if (name_i.equals(name_j)) {
env.error(lf2.getWhere(), "duplicate.argument",
name_i);
break outer_loop;
}
}
}
}
if (getValue() != null) {
ctx = new Context(ctx, this);
if (isMethod()) {
Statement s = (Statement)getValue();
// initialize vset, indication that each of the arguments
// to the function has a value
for (Enumeration e = args.elements(); e.hasMoreElements();){
LocalMember f = (LocalMember)e.nextElement();
vset.addVar(ctx.declare(env, f));
}
if (isConstructor()) {
// Undefine "this" in some constructors, until after
// the super constructor has been called.
vset.clearVar(ctx.getThisNumber());
// If the first thing in the definition isn't a call
// to either super() or this(), then insert one.
Expression supCall = s.firstConstructor();
if ((supCall == null)
&& (getClassDefinition().getSuperClass() != null)) {
supCall = getDefaultSuperCall(env);
Statement scs = new ExpressionStatement(where,
supCall);
s = Statement.insertStatement(scs, s);
setValue(s);
}
}
//System.out.println("VSET = " + vset);
ClassDeclaration exp[] = getExceptions(env);
int htsize = (exp.length > 3) ? 17 : 7;
Hashtable thrown = new Hashtable(htsize);
vset = s.checkMethod(env, ctx, vset, thrown);
ClassDeclaration ignore1 =
env.getClassDeclaration(idJavaLangError);
ClassDeclaration ignore2 =
env.getClassDeclaration(idJavaLangRuntimeException);
for (Enumeration e = thrown.keys(); e.hasMoreElements();) {
ClassDeclaration c = (ClassDeclaration)e.nextElement();
ClassDefinition def = c.getClassDefinition(env);
if (def.subClassOf(env, ignore1)
|| def.subClassOf(env, ignore2)) {
continue;
}
boolean ok = false;
if (!isInitializer()) {
for (int i = 0 ; i < exp.length ; i++) {
if (def.subClassOf(env, exp[i])) {
ok = true;
}
}
}
if (!ok) {
Node n = (Node)thrown.get(c);
long where = n.getWhere();
String errorMsg;
if (isConstructor()) {
if (where ==
getClassDefinition().getWhere()) {
// If this message is being generated for
// a default constructor, we should give
// a different error message. Currently
// we check for this by seeing if the
// constructor has the same "where" as
// its class. This is a bit kludgy, but
// works. (bug id 4034836)
errorMsg = "def.constructor.exception";
} else {
// Constructor with uncaught exception.
errorMsg = "constructor.exception";
}
} else if (isInitializer()) {
// Initializer with uncaught exception.
errorMsg = "initializer.exception";
} else {
// Method with uncaught exception.
errorMsg = "uncaught.exception";
}
env.error(where, errorMsg, c.getName());
}
}
} else {
Hashtable thrown = new Hashtable(3); // small & throw-away
Expression val = (Expression)getValue();
vset = val.checkInitializer(env, ctx, vset,
getType(), thrown);
setValue(val.convert(env, ctx, getType(), val));
// Complain about static final members of inner classes that
// do not have an initializer that is a constant expression.
// In general, static members are not permitted for inner
// classes, but an exception is made for named constants.
// Other cases of static members, including non-final ones,
// are handled in 'SourceClass'. Part of fix for 4095568.
if (isStatic() && isFinal() && !clazz.isTopLevel()) {
if (!((Expression)getValue()).isConstant()) {
env.error(where, "static.inner.field", getName(), this);
setValue(null);
}
}
// Both RuntimeExceptions and Errors should be
// allowed in initializers. Fix for bug 4102541.
ClassDeclaration except =
env.getClassDeclaration(idJavaLangThrowable);
ClassDeclaration ignore1 =
env.getClassDeclaration(idJavaLangError);
ClassDeclaration ignore2 =
env.getClassDeclaration(idJavaLangRuntimeException);
for (Enumeration e = thrown.keys(); e.hasMoreElements(); ) {
ClassDeclaration c = (ClassDeclaration)e.nextElement();
ClassDefinition def = c.getClassDefinition(env);
if (!def.subClassOf(env, ignore1)
&& !def.subClassOf(env, ignore2)
&& def.subClassOf(env, except)) {
Node n = (Node)thrown.get(c);
env.error(n.getWhere(),
"initializer.exception", c.getName());
}
}
}
if (env.dump()) {
getValue().print(System.out);
System.out.println();
}
}
status = getClassDefinition().getError() ? ERROR : CHECKED;
}
// Initializers (static and instance) must be able to complete normally.
if (isInitializer() && vset.isDeadEnd()) {
env.error(where, "init.no.normal.completion");
vset = vset.clearDeadEnd();
}
return vset;
}
// helper to check(): synthesize a missing super() call
private Expression getDefaultSuperCall(Environment env) {
Expression se = null;
ClassDefinition sclass = getClassDefinition().getSuperClass().getClassDefinition();
// does the superclass constructor require an enclosing instance?
ClassDefinition reqc = (sclass == null) ? null
: sclass.isTopLevel() ? null
: sclass.getOuterClass();
ClassDefinition thisc = getClassDefinition();
if (reqc != null && !Context.outerLinkExists(env, reqc, thisc)) {
se = new SuperExpression(where, new NullExpression(where));
env.error(where, "no.default.outer.arg", reqc, getClassDefinition());
}
if (se == null) {
se = new SuperExpression(where);
}
return new MethodExpression(where, se, idInit, new Expression[0]);
}
Inline the field
/**
* Inline the field
*/
void inline(Environment env) throws ClassNotFound {
switch (status) {
case PARSED:
check(env);
inline(env);
break;
case CHECKED:
if (env.dump()) {
System.out.println("[inline field " + getClassDeclaration().getName() + "." + getName() + "]");
}
status = INLINING;
env = new Environment(env, this);
if (isMethod()) {
if ((!isNative()) && (!isAbstract())) {
Statement s = (Statement)getValue();
Context ctx = new Context((Context)null, this);
for (Enumeration e = args.elements() ; e.hasMoreElements() ;) {
LocalMember local = (LocalMember)e.nextElement();
ctx.declare(env, local);
}
setValue(s.inline(env, ctx));
}
} else if (isInnerClass()) {
// some classes are checked and inlined separately
ClassDefinition nc = getInnerClass();
if (nc instanceof SourceClass && !nc.isLocal()
&& nc.isInsideLocal()) {
status = INLINING;
((SourceClass)nc).inlineLocalClass(env);
}
status = INLINED;
break;
} else {
if (getValue() != null) {
Context ctx = new Context((Context)null, this);
if (!isStatic()) {
// Cf. "thisArg" in SourceClass.checkMembers().
Context ctxInst = new Context(ctx, this);
LocalMember thisArg =
((SourceClass)clazz).getThisArgument();
ctxInst.declare(env, thisArg);
setValue(((Expression)getValue())
.inlineValue(env, ctxInst));
} else {
setValue(((Expression)getValue())
.inlineValue(env, ctx));
}
}
}
if (env.dump()) {
System.out.println("[inlined field " + getClassDeclaration().getName() + "." + getName() + "]");
if (getValue() != null) {
getValue().print(System.out);
System.out.println();
} else {
System.out.println("<empty>");
}
}
status = INLINED;
break;
}
}
Get the value of the field (or null if the value can't be determined)
/**
* Get the value of the field (or null if the value can't be determined)
*/
public Node getValue(Environment env) throws ClassNotFound {
Node value = getValue();
if (value != null && status != INLINED) {
// be sure to get the imports right:
env = ((SourceClass)clazz).setupEnv(env);
inline(env);
value = (status == INLINED) ? getValue() : null;
}
return value;
}
public boolean isInlineable(Environment env, boolean fromFinal) throws ClassNotFound {
if (super.isInlineable(env, fromFinal)) {
getValue(env);
return (status == INLINED) && !getClassDefinition().getError();
}
return false;
}
Get the initial value of the field
/**
* Get the initial value of the field
*/
public Object getInitialValue() {
if (isMethod() || (getValue() == null) || (!isFinal()) || (status != INLINED)) {
return null;
}
return ((Expression)getValue()).getValue();
}
Generate code
/**
* Generate code
*/
public void code(Environment env, Assembler asm) throws ClassNotFound {
switch (status) {
case PARSED:
check(env);
code(env, asm);
return;
case CHECKED:
inline(env);
code(env, asm);
return;
case INLINED:
// Actually generate code
if (env.dump()) {
System.out.println("[code field " + getClassDeclaration().getName() + "." + getName() + "]");
}
if (isMethod() && (!isNative()) && (!isAbstract())) {
env = new Environment(env, this);
Context ctx = new Context((Context)null, this);
Statement s = (Statement)getValue();
for (Enumeration e = args.elements() ; e.hasMoreElements() ; ) {
LocalMember f = (LocalMember)e.nextElement();
ctx.declare(env, f);
//ctx.declare(env, (LocalMember)e.nextElement());
}
/*
if (isConstructor() && ((s == null) || (s.firstConstructor() == null))) {
ClassDeclaration c = getClassDefinition().getSuperClass();
if (c != null) {
MemberDefinition field = c.getClassDefinition(env).matchMethod(env, getClassDefinition(), idInit);
asm.add(getWhere(), opc_aload, new Integer(0));
asm.add(getWhere(), opc_invokespecial, field);
asm.add(getWhere(), opc_pop);
}
// Output initialization code
for (MemberDefinition f = getClassDefinition().getFirstMember() ; f != null ; f = f.getNextMember()) {
if (!f.isStatic()) {
f.codeInit(env, ctx, asm);
}
}
}
*/
if (s != null) {
s.code(env, ctx, asm);
}
if (getType().getReturnType().isType(TC_VOID) && !isInitializer()) {
asm.add(getWhere(), opc_return, true);
}
}
return;
}
}
public void codeInit(Environment env, Context ctx, Assembler asm) throws ClassNotFound {
if (isMethod()) {
return;
}
switch (status) {
case PARSED:
check(env);
codeInit(env, ctx, asm);
return;
case CHECKED:
inline(env);
codeInit(env, ctx, asm);
return;
case INLINED:
// Actually generate code
if (env.dump()) {
System.out.println("[code initializer " + getClassDeclaration().getName() + "." + getName() + "]");
}
if (getValue() != null) {
Expression e = (Expression)getValue();
// The JLS Section 8.5 specifies that static (non-final)
// initializers should be executed in textual order. Eliding
// initializations to default values can interfere with this,
// so the tests for !e.equalsDefault() have been eliminated,
// below.
if (isStatic()) {
if (getInitialValue() == null) {
// removed: && !e.equalsDefault()) {
e.codeValue(env, ctx, asm);
asm.add(getWhere(), opc_putstatic, this);
}
} else { // removed: if (!e.equalsDefault()) {
// This code doesn't appear to be reached for
// instance initializers. Code for these is generated
// in the makeVarInits() method of the class
// MethodExpression.
asm.add(getWhere(), opc_aload, new Integer(0));
e.codeValue(env, ctx, asm);
asm.add(getWhere(), opc_putfield, this);
}
}
return;
}
}
Print for debugging
/**
* Print for debugging
*/
public void print(PrintStream out) {
super.print(out);
if (getValue() != null) {
getValue().print(out);
out.println();
}
}
}