/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* 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.
*/
public
// The class from which the field is select ed.
// For an expression of the form '<class>.super', then
// this is <class>, else null.
/**
* constructor
*/
}
}
if (implementation != null)
return implementation;
return this;
}
/**
* Return true if the field is being selected from
* a qualified 'super'.
*/
private boolean isQualSuper() {
}
/**
* Convert an '.' expression to a qualified identifier
*/
return null;
}
}
return null;
}
}
/**
* Convert a qualified name into a type.
* Performs a careful check of each inner-class component,
* including the JLS 6.6.1 access checks that were omitted
* in 'FieldExpression.toType'.
* <p>
* This code is similar to 'checkCommon', which could be cleaned
* up a bit long the lines we have done here.
*/
/*-------------------------------------------------------*
Type toQualifiedType(Environment env, Context ctx) {
ClassDefinition ctxClass = ctx.field.getClassDefinition();
Type rty = right.toQualifiedType(env, ctx);
if (rty == Type.tPackage) {
// Is this field expression a non-inner type?
Identifier nm = toIdentifier(this);
if ((nm != null) && env.classExists(nm)) {
Type t = Type.tClass(nm);
if (env.resolve(where, ctxClass, t)) {
return t;
} else {
return null;
}
}
// Not a type. Must be a package prefix.
return Type.tPackage;
}
if (rty == null) {
// An error was already reported, so quit.
return null;
}
// Check inner-class qualification while unwinding from recursion.
try {
ClassDefinition rightClass = env.getClassDefinition(rty);
// Local variables, which cannot be inner classes,
// are ignored here, and thus will not hide inner
// classes. Is this correct?
MemberDefinition field = rightClass.getInnerClass(env, id);
if (field == null) {
env.error(where, "inner.class.expected", id, rightClass);
return Type.tError;
}
ClassDefinition innerClass = field.getInnerClass();
Type t = innerClass.getType();
if (!ctxClass.canAccess(env, field)) {
env.error(where, "no.type.access", id, rightClass, ctxClass);
return t;
}
if (field.isProtected()
&& !ctxClass.protectedAccess(env, field, rty)) {
env.error(where, "invalid.protected.type.use", id, ctxClass, rty);
return t;
}
// These were ommitted earlier in calls to 'toType', but I can't
// see any reason for that. I think it was an oversight. See
// 'checkCommon' and 'checkInnerClass'.
innerClass.noteUsedBy(ctxClass, where, env);
ctxClass.addDependency(field.getClassDeclaration());
return t;
} catch (ClassNotFound e) {
env.error(where, "class.not.found", e.name, ctx.field);
}
// Class not found.
return null;
}
*-------------------------------------------------------*/
/**
* Convert an '.' expression to a type
*/
// This is a rewrite to treat qualified names in a
// context in which a type name is expected in the
// same way that they are handled for an ambiguous
// or expression-expected context in 'checkCommon'
// below. The new code is cleaner and allows better
// localization of errors. Unfortunately, most
// qualified names appearing in types are actually
// handled by 'Environment.resolve'. There isn't
// much point, then, in breaking out 'toType' as a
// special case until the other cases can be cleaned
// up as well. For the time being, we will leave this
// code disabled, thus reducing the testing requirements.
/*-------------------------------------------------------*
Type toType(Environment env, Context ctx) {
Type t = toQualifiedType(env, ctx);
if (t == null) {
return Type.tError;
}
if (t == Type.tPackage) {
FieldExpression.reportFailedPackagePrefix(env, right, true);
return Type.tError;
}
return t;
}
*-------------------------------------------------------*/
}
return t;
}
}
/**
* Check if the present name is part of a scoping prefix.
*/
}
}
/**
* Check the expression
*/
// "super" is not allowed in this context.
// It must always qualify another name.
}
return vset;
}
/**
* If 'checkAmbiguousName' returns 'Package.tPackage', then it was
* unable to resolve any prefix of the qualified name. This method
* attempts to diagnose the problem.
*/
}
boolean mustBeType) {
// Find the leftmost component, and put the blame on it.
while (idp instanceof UnaryExpression)
// It may be that 'ie' refers to an ambiguous class. Check this
// with a call to env.resolve(). Part of solution for 4059855.
try {
} catch (AmbiguousClass e) {
return;
} catch (ClassNotFound e) {
}
if (mustBeType) {
} else {
}
} else {
if (mustBeType) {
} else {
}
}
}
/**
* Rewrite accesses to private fields of another class.
*/
private Expression
// If the field is final and its initializer is a constant expression,
// then just rewrite to the constant expression. This is not just an
// optimization, but is required for correctness. If an expression is
// rewritten to use an access method, then its status as a constant
// expression is lost. This was the cause of bug 4098737. Note that
// a call to 'getValue(env)' below would not be correct, as it attempts
// to simplify the initial value expression, which must not occur until
// after the checking phase, for example, after definite assignment checks.
// Must not be LHS here. Test as a precaution,
// as we may not be careful to avoid this when
// compiling an erroneous program.
return e.copyInline(ctx);
}
}
//System.out.println("Finding access method for " + field);
//System.out.println("Using access method " + af);
if (!isLHS) {
//System.out.println("Reading " + field +
// " via access method " + af);
// If referencing the value of the field, then replace
// with a call to the access method. If assigning to
// the field, a call to the update method will be
// generated later. It is important that
// 'implementation' not be set to non-null if the
// expression is a valid assignment target.
// (See 'checkLHS'.)
Expression args[] = { };
} else {
}
}
}
return null;
}
/**
* Determine if an access method is required, and, if so, return
* the class in which it should appear, else return null.
*/
// If access from same class as field, then no access
// method is needed.
return null;
}
// An access method is needed in the class containing the field.
return cdef;
} else if (field.isProtected()) {
// If access is not via qualified super, then it is either
// OK without an access method, or it is an illegal access
// for which an error message should have been issued.
// Legal accesses include unqualified 'super.foo'.
return null;
}
// Access to protected member in same package always allowed.
return null;
}
// Access via qualified super.
// An access method is needed in the qualifying class, an
// immediate subclass of the class containing the selected
// field. NOTE: The fact that the returned class is 'superBase'
// carries the additional bit of information (that a special
// superclass access method is being created) which is provided
// to 'getAccessMember' via its 'isSuper' argument.
return superBase;
} else {
// No access method needed.
return null;
}
}
/**
* Determine if a type is accessible from a given class.
*/
Type t,
ClassDefinition c) {
switch (t.getTypeCode()) {
case TC_CLASS:
try {
// Why not just use 'Environment.getClassDeclaration' here?
// But 'Environment.getClassDeclation' has special treatment
// for local classes that is probably necessary. This code
// was adapted from 'Environment.resolve'.
} catch (ClassNotFound e) {} // Ignore -- reported elsewhere.
return true;
case TC_ARRAY:
default:
return true;
}
}
/**
* Common code for checkValue and checkAmbigName
*/
// Handle class literal, e.g., 'x.class'.
// In 'x.class', 'x' must be a type name, possibly qualified.
return vset;
}
switch (t.getTypeCode()) {
default:
return vset;
}
return vset;
}
// Check for the bogus type `array of void'
if (t.isVoidArray()) {
return vset;
}
// it is a class or array
// We assume SIG_CLASS and SIG_ENDCLASS are 1 char each.
} else {
// name is like "[Lfoo.bar" or (again) "[I".
}
if (fcls.isInterface()) {
// The immediately-enclosing type is an interface.
// The class literal can only appear in an initialization
// expression, so don't bother caching it. (This could
// lose if many initializations use the same class literal,
// but saves time and code space otherwise.)
} else {
// Cache the call to the helper, as it may be executed
// many times (e.g., if the class literal is inside a loop).
}
return vset;
}
// Arrive here if not a class literal.
// The field as been pre-set, e.g., as the result of transforming
// an 'IdentifierExpression'. Most error-checking has already been
// performed at this point.
// QUERY: Why don't we further unify checking of identifier
// expressions and field expressions that denote instance and
// class variables?
}
// Does the qualifier have a meaning of its own?
// Are we out of options?
return vset;
}
// ASSERT(loc.right == this)
// Nope. Is this field expression a type?
// Check access. (Cf. IdentifierExpression.toResolvedType.)
return vset;
}
// Let the caller make sense of it, then.
return vset;
}
// Good; we have a well-defined qualifier type.
try {
// Handle array 'length' field, e.g., 'x.length'.
// Verify that the type of the base expression is accessible.
// Required by JLS 6.6.1. Fixes 4094658.
if (staticRef) {
} else {
}
}
return vset;
}
}
return vset;
}
// At this point, we know that 'right.type' is a class type.
// Note that '<expr>.super(...)' and '<expr>.this(...)' cases never
// reach here. Instead, '<expr>' is stored as the 'outerArg' field
// of a 'SuperExpression' or 'ThisExpression' node.
// If our prefix is of the form '<class>.super', then we are
// about to do a field selection '<class>.super.<field>'.
// Save the qualifying class in 'superBase', which is non-null
// only if the current FieldExpression is a qualified 'super' form.
// Also, set 'sourceClass' to the "effective accessing class" relative
// to which access checks will be performed. Normally, this is the
// immediately enclosing class. For '<class>.this' and '<class>.super',
// however, we use <class>.
if (right instanceof FieldExpression) {
}
}
// Handle 'class.this' and 'class.super'.
//
// Suppose 'super.name' appears within a class C with immediate
// superclass S. According to JLS 15.10.2, 'super.name' in this
// case is equivalent to '((S)this).name'. Analogously, we interpret
// 'class.super.name' as '((S)(class.this)).name', where S is the
// immediate superclass of (enclosing) class 'class'.
// Note that 'super' may not stand alone as an expression, but must
// occur as the qualifying expression of a field access or a method
// invocation. This is enforced in 'SuperExpression.checkValue' and
// 'FieldExpression.checkValue', and need not concern us here.
//ClassDefinition clazz = env.getClassDefinition(right.type);
if (!staticRef) {
}
// We used to check that 'right.type' is accessible here,
// per JLS 6.6.1. As a result of the fix for 4102393, however,
// the qualifying class name must exactly match an enclosing
// outer class, which is necessarily accessible.
/*** Temporary assertion check ***/
throw new CompilerError("synthetic qualified this");
/*********************************/
// A.this means we're inside an A and we want its self ptr.
// C.this is always the same as this when C is innermost.
// Another A.this means we skip out to get a "hidden" this,
// just as ASuper.foo skips out to get a hidden variable.
// Last argument 'true' means we want an exact class match,
// not a subclass of the specified class ('clazz').
} else {
}
return vset;
}
// Field should be an instance variable or class variable.
// Is this field expression an inner type?
// Search the class and its supers (but not its outers).
// QUERY: We may need to get the inner class from a
// superclass of 'clazz'. This call is prepared to
// resolve the superclass if necessary. Can we arrange
// to assure that it is always previously resolved?
// This is one of a small number of problematic calls that
// requires 'getSuperClass' to resolve superclasses on demand.
// See 'ClassDefinition.getInnerClass(env, nm)'.
}
}
// If not a variable reference, diagnose error if name is
// that of a method.
} else {
}
return vset;
}
// At this point, we have identified a valid field.
// Required by JLS 6.6.1. Fixes 4094658.
if (staticRef) {
} else {
}
}
return vset;
}
// 'Class.field' is not legal when field is not static;
// see JLS 15.13.1. This case was permitted by javac
// prior to 1.2; static refs were silently changed to
// be dynamic access of the form 'this.field'.
return vset;
} else {
// Rewrite access to use an access method if necessary.
}
// Check for invalid access to protected field.
if (field.isProtected()
&& !(right instanceof SuperExpression
// Extension of JLS 6.6.2 for qualified 'super'.
|| (right instanceof FieldExpression &&
return vset;
}
}
}
// When a package-private class defines public or protected
// members, those members may sometimes be accessed from
// outside of the package in public subclasses. In these
// cases, we need to massage the getField to refer to
// to an accessible subclass rather than the package-private
// parent class. Part of fix for 4135692.
// Find out if the class which contains this field
// reference has access to the class which declares the
// public or protected field.
if (sourceClass == ctxClass) {
if (declarer.isPackagePrivate() &&
//System.out.println("The access of member " +
// field + " declared in class " +
// declarer +
// " is not allowed by the VM from class " +
// ctxClass +
// ". Replacing with an access of class " +
// clazz);
// We cannot make this access at the VM level.
// Construct a member which will stand for this
// field in ctxClass and set `field' to refer to it.
field =
}
}
} catch (ClassNotFound e) {
} catch (AmbiguousMember e) {
}
return vset;
}
/**
* Return a <code>FieldUpdater</code> object to be used in updating the
* value of the location denoted by <code>this</code>, which must be an
* expression suitable for the left-hand side of an assignment.
* This is used for implementing assignments to private fields for which
* an access method is required. Returns null if no access method is
* needed, in which case the assignment is handled in the usual way, by
* direct access. Only simple assignment expressions are handled here
* are handled by 'getUpdater' below.
* <p>
* Must be called after 'checkValue', else 'right' will be invalid.
*/
// Field can legitimately be null if the field name was
// undefined, in which case an error was reported, but
// no value for 'field' is available.
// throw new CompilerError("getAssigner");
return null;
}
// It may not be necessary to copy 'right' here.
// Created 'FieldUpdater' has no getter method.
}
return null;
}
/**
* Return a <code>FieldUpdater</code> object to be used in updating the
* value of the location denoted by <code>this</code>, which must be an
* expression suitable for the left-hand side of an assignment. This is
* used for implementing the assignment operators and the increment and
* decrement operators on private fields that are accessed from another
* class, e.g, uplevel from an inner class. Returns null if no access
* method is needed.
* <p>
* Must be called after 'checkValue', else 'right' will be invalid.
*/
// Field can legitimately be null if the field name was
// undefined, in which case an error was reported, but
// no value for 'field' is available.
// throw new CompilerError("getUpdater");
return null;
}
// It may not be necessary to copy 'right' here.
}
return null;
}
/**
* This field expression is an inner class reference.
* Finish checking it.
*/
if (!inner.isTopLevel()) {
}
// check access
try {
//env.error(where, "no.type.access",
// id, clazz, ctx.field.getClassDeclaration());
return vset;
}
if (field.isProtected()
&& !(right instanceof SuperExpression
// Extension of JLS 6.6.2 for qualified 'super'.
|| (right instanceof FieldExpression &&
return vset;
}
} catch (ClassNotFound e) {
}
// Complain about a free-floating type name.
return vset;
}
/**
* Check the expression if it appears on the LHS of an assignment
*/
//checkValue(env, ctx, vset, exp);
// If 'implementation' is set to a non-null value, then the
// field expression does not denote an assignable location,
// e.g., the 'length' field of an array.
if (implementation != null) {
// This just reports an error and recovers.
}
if (field.isBlankFinal()) {
}
// Continue with checking anyhow.
// In fact, it would be easy to allow this case.
} else {
// The actual instance could be anywhere, so don't
// continue with checking the definite assignment status.
return vset;
}
}
} else {
}
}
return vset;
}
/**
* Check the expression if it appears on the LHS of an op= expression
*/
//checkValue(env, ctx, vset, exp);
// If 'implementation' is set to a non-null value, then the
// field expression does not denote an assignable location,
// e.g., the 'length' field of an array.
if (implementation != null) {
}
}
return vset;
}
/**
* There is a simple assignment being made to the given final field.
* The field was named either by a simple name or by an almost-simple
* expression of the form "this.v".
* Check if this is a legal assignment.
* <p>
* Blank final variables can be set in initializers or constructor
* bodies. In all cases there must be definite single assignment.
* (All instance and instance variable initializers and each
* constructor body are treated as if concatenated for the purposes
* of this check. Assignment to "this.x" is treated as a definite
* assignment to the simple name "x" which names the instance variable.)
*/
if (field.isBlankFinal()
// definite single assignment
} else {
// it is a blank final in this class, but not assignable
}
} else {
// give the generic error message
}
return vset;
}
ClassDefinition c) {
// Given a class name, look for a static field to cache it.
// className lname
// pkg.Foo class$pkg$Foo
// [Lpkg.Foo; array$Lpkg$Foo
// [[Lpkg.Foo; array$$Lpkg$Foo
// [I array$I
// [[I array$$I
} else {
// [Lpkg.Foo; => array$Lpkg$Foo
}
// else [I => array$I or some such; lname is already OK
}
// The class to put the cache in is now given as an argument.
//
// ClassDefinition c = ctx.field.getClassDefinition();
// while (c.isInnerClass()) {
// c = c.getOuterClass();
try {
} catch (ClassNotFound ee) {
return null;
} catch (AmbiguousMember ee) {
return null;
}
// Ignore inherited field. Each top-level class
// containing a given class literal must have its own copy,
// both for reasons of binary compatibility and to prevent
// access violations should the superclass be in another
// package. Part of fix 4106051.
return cfld;
}
// Since each class now has its own copy, we might as well
// tighten up the access to private (previously default).
// Part of fix for 4106051.
// ** Temporarily retract this, as it tickles 4098316.
c, null,
}
.getType());
new NullExpression(where));
setCache);
}
return getClass;
}
/**
* Check if constant: Will it inline away?
*/
public boolean isConstant() {
if (implementation != null)
return implementation.isConstant();
return field.isConstant();
}
return false;
}
/**
* Inline
*/
if (implementation != null)
// A field expression may have the side effect of causing
// a NullPointerException, so evaluate it even though
// the value is not needed. Similarly, static field dereferences
// may cause class initialization, so they mustn't be omitted
// either.
//
// However, NullPointerException can't happen and initialization must
// already have occured if you are dotting into 'this'. So
// allow fields of 'this' to be eliminated as a special case.
if (e instanceof FieldExpression) {
return null;
// It should be possible to split this into two checks: one using
// isNonNull() for non-statics and a different check for statics.
// That would make the inlining slightly less conservative by
// allowing, for example, dotting into String constants.
}
return e;
}
if (implementation != null)
try {
return this;
}
if ((e != null) && e.isConstant()) {
// remove bogus line-number info
e = e.copyInline(ctx);
}
}
if (e != null) {
return new CommaExpression(where, e, this);
}
} else {
}
}
return this;
} catch (ClassNotFound e) {
throw new CompilerError(e);
}
}
if (implementation != null)
if (e != null) {
return new CommaExpression(where, e, this);
}
} else {
}
}
return this;
}
if (implementation != null)
return super.copyInline(ctx);
}
/**
* The cost of inlining this expression
*/
if (implementation != null)
}
// ctxClass is the current class trying to inline this method
try {
// We only allow the inlining if the current class can access
// the field, the field's class, and right's declared type.
return 3;
} else {
}
}
}
} catch (ClassNotFound e) {
}
return thresh;
}
/**
* Code
*/
if (implementation != null)
throw new CompilerError("codeLValue");
return 1;
}
return 0;
}
return 1;
}
throw new CompilerError("should not be null");
}
} else {
}
}
} else {
}
}
}
/**
* Print
*/
} else {
}
if (implementation != null) {
}
}
}