001: /*
002: * Copyright 1997-2003 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.tree;
027:
028: import sun.tools.java.*;
029: import sun.tools.asm.Assembler;
030: import java.io.PrintStream;
031:
032: /**
033: * This class encapsulates the information required to generate an update to a private
034: * field referenced from another class, e.g., an inner class. An expression denoting a
035: * reference to the object to which the field belongs is associated with getter and
036: * setter methods.
037: * <p>
038: * We use this class only for assignment, increment, and decrement operators, in which
039: * the old value is first retrieved and then a new value is computed and stored.
040: * Simple assignment expressions in which a value is copied without modification are
041: * handled by another mechanism.
042: *
043: * WARNING: The contents of this source file are not part of any
044: * supported API. Code that depends on them does so at its own risk:
045: * they are subject to change or removal without notice.
046: */
047:
048: class FieldUpdater implements Constants {
049:
050: // Location for reporting errors.
051: // Errors will always indicate compiler failure, but these will be easier to diagnose
052: // if the bogus error is localized to the offending assignment.
053: private long where;
054:
055: // The field to which this updater applies.
056: // It would be easy to eliminate the need to store the field here, but we retain it for
057: // diagnostic purposes.
058: private MemberDefinition field;
059:
060: // Expression denoting the object to which the getter and setter are applied.
061: // If the field is static, 'base' may be null, but need not be, as a static field
062: // may be selected from an object reference. Even though the value of the object
063: // reference will be ignored, it may have side-effects.
064: private Expression base;
065:
066: // The getter and setter methods, generated by 'getAccessMember' and 'getUpdateMember'.
067: private MemberDefinition getter;
068: private MemberDefinition setter;
069:
070: // The number of words occupied on the stack by the object reference.
071: // For static fields, this is zero.
072: private int depth;
073:
074: /**
075: * Constructor.
076: */
077:
078: public FieldUpdater(long where, MemberDefinition field,
079: Expression base, MemberDefinition getter,
080: MemberDefinition setter) {
081: this .where = where;
082: this .field = field;
083: this .base = base;
084: this .getter = getter;
085: this .setter = setter;
086: }
087:
088: /**
089: * Since the object reference expression may be captured before it has been inlined,
090: * we must inline it later. A <code>FieldUpdater</code> is inlined essentially as if
091: * it were a child of the assignment node to which it belongs.
092: */
093:
094: public FieldUpdater inline(Environment env, Context ctx) {
095: if (base != null) {
096: if (field.isStatic()) {
097: base = base.inline(env, ctx);
098: } else {
099: base = base.inlineValue(env, ctx);
100: }
101: }
102: return this ;
103: }
104:
105: public FieldUpdater copyInline(Context ctx) {
106: return new FieldUpdater(where, field, base.copyInline(ctx),
107: getter, setter);
108: }
109:
110: public int costInline(int thresh, Environment env, Context ctx,
111: boolean needGet) {
112: // Size of 'invokestatic' call for access method is 3 bytes.
113: int cost = needGet ? 7 : 3; // getter needs extra invokestatic + dup
114: // Size of expression to compute 'this' arg if needed.
115: if (!field.isStatic() && base != null) {
116: cost += base.costInline(thresh, env, ctx);
117: }
118: // We ignore the cost of duplicating value in value-needed context.
119: return cost;
120: }
121:
122: /**
123: * Duplicate <code>items</code> words from the top of the stack, locating them
124: * below the topmost <code>depth</code> words on the stack.
125: */
126:
127: // This code was cribbed from 'Expression.java'. We cannot reuse that code here,
128: // because we do not inherit from class 'Expression'.
129: private void codeDup(Assembler asm, int items, int depth) {
130: switch (items) {
131: case 0:
132: return;
133: case 1:
134: switch (depth) {
135: case 0:
136: asm.add(where, opc_dup);
137: return;
138: case 1:
139: asm.add(where, opc_dup_x1);
140: return;
141: case 2:
142: asm.add(where, opc_dup_x2);
143: return;
144:
145: }
146: break;
147: case 2:
148: switch (depth) {
149: case 0:
150: asm.add(where, opc_dup2);
151: return;
152: case 1:
153: asm.add(where, opc_dup2_x1);
154: return;
155: case 2:
156: asm.add(where, opc_dup2_x2);
157: return;
158:
159: }
160: break;
161: }
162: throw new CompilerError("can't dup: " + items + ", " + depth);
163: }
164:
165: /**
166: * Begin a field update by an assignment, increment, or decrement operator.
167: * The current value of the field is left at the top of the stack.
168: * If <code>valNeeded</code> is true, we arrange for the initial value to remain
169: * on the stack after the update.
170: */
171:
172: public void startUpdate(Environment env, Context ctx,
173: Assembler asm, boolean valNeeded) {
174: if (!(getter.isStatic() && setter.isStatic())) {
175: throw new CompilerError("startUpdate isStatic");
176: }
177: if (!field.isStatic()) {
178: // Provide explicit 'this' argument.
179: base.codeValue(env, ctx, asm);
180: depth = 1;
181: } else {
182: // May need to evaluate 'base' for effect.
183: // If 'base' was a type expression, it should have previously been inlined away.
184: if (base != null) {
185: base.code(env, ctx, asm);
186: }
187: depth = 0;
188: }
189: codeDup(asm, depth, 0);
190: asm.add(where, opc_invokestatic, getter);
191: if (valNeeded) {
192: codeDup(asm, field.getType().stackSize(), depth);
193: }
194: }
195:
196: /**
197: * Complete a field update by an assignment, increment, or decrement operator.
198: * The original value of the field left on the stack by <code>startUpdate</code>
199: * must have been replaced with the updated value, with no other stack alterations.
200: * If <code>valNeeded</code> is true, we arrange for the updated value to remain
201: * on the stack after the update. The <code>valNeeded</code> argument must not be
202: * true in both <code>startUpdate</code> and <code>finishUpdate</code>.
203: */
204:
205: public void finishUpdate(Environment env, Context ctx,
206: Assembler asm, boolean valNeeded) {
207: if (valNeeded) {
208: codeDup(asm, field.getType().stackSize(), depth);
209: }
210: asm.add(where, opc_invokestatic, setter);
211: }
212:
213: /**
214: * Like above, but used when assigning a new value independent of the
215: * old, as in a simple assignment expression. After 'startAssign',
216: * code must be emitted to leave one additional value on the stack without
217: * altering any others, followed by 'finishAssign'.
218: */
219:
220: public void startAssign(Environment env, Context ctx, Assembler asm) {
221: if (!setter.isStatic()) {
222: throw new CompilerError("startAssign isStatic");
223: }
224: if (!field.isStatic()) {
225: // Provide explicit 'this' argument.
226: base.codeValue(env, ctx, asm);
227: depth = 1;
228: } else {
229: // May need to evaluate 'base' for effect.
230: // If 'base' was a type expression, it should have previously been inlined away.
231: if (base != null) {
232: base.code(env, ctx, asm);
233: }
234: depth = 0;
235: }
236: }
237:
238: public void finishAssign(Environment env, Context ctx,
239: Assembler asm, boolean valNeeded) {
240: if (valNeeded) {
241: codeDup(asm, field.getType().stackSize(), depth);
242: }
243: asm.add(where, opc_invokestatic, setter);
244: }
245:
246: }
|