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/tree/UplevelReference.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/tools/tree/UplevelReference.java+401−0
@@ -0,0 +1,401 @@
1+/*
2+ * Copyright (c) 1997, 2003, 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+
26+package sun.tools.tree;
27+
28+import sun.tools.java.*;
29+import sun.tools.tree.*;
30+import sun.tools.asm.Assembler;
31+
32+/**
33+ * A reference from one scope to another.
34+ *
35+ * WARNING: The contents of this source file are not part of any
36+ * supported API. Code that depends on them does so at its own risk:
37+ * they are subject to change or removal without notice.
38+ *
39+ */
40+
41+public
42+class UplevelReference implements Constants {
43+ /**
44+ * The class in which the reference occurs.
45+ */
46+ ClassDefinition client;
47+
48+ /**
49+ * The field being referenced.
50+ * It is always a final argument or a final local variable.
51+ * (An uplevel reference to a field of a class C is fetched
52+ * through an implicit uplevel reference to C.this, which is
53+ * an argument.)
54+ */
55+ LocalMember target;
56+
57+ /**
58+ * The local variable which bears a copy of the target's value,
59+ * for all methods of the client class.
60+ * Its name is "this$C" for <code>this.C</code> or
61+ * "val$x" for other target variables <code>x</code>.
62+ * <p>
63+ * This local variable is always a constructor argument,
64+ * and is therefore usable only in the constructor and in initializers.
65+ * All other methods use the local field.
66+ * @see #localField
67+ */
68+ LocalMember localArgument;
69+
70+ /**
71+ * A private synthetic field of the client class which
72+ * bears a copy of the target's value.
73+ * The compiler tries to avoid creating it if possible.
74+ * The field has the same name and type as the localArgument.
75+ * @see #localArgument
76+ */
77+ MemberDefinition localField;
78+
79+ /**
80+ * The next item on the references list of the client.
81+ */
82+ UplevelReference next;
83+
84+ /**
85+ * constructor
86+ */
87+ public UplevelReference(ClassDefinition client, LocalMember target) {
88+ this.client = client;
89+ this.target = target;
90+
91+ // Choose a name and build a variable declaration node.
92+ Identifier valName;
93+ if (target.getName().equals(idThis)) {
94+ ClassDefinition tc = target.getClassDefinition();
95+ // It should always be true that tc.enclosingClassOf(client).
96+ // If it were false, the numbering scheme would fail
97+ // to produce unique names, since we'd be trying
98+ // to number classes which were not in the sequence
99+ // of enclosing scopes. The next paragraph of this
100+ // code robustly deals with that possibility, however,
101+ // by detecting name collisions and perturbing the names.
102+ int depth = 0;
103+ for (ClassDefinition pd = tc; !pd.isTopLevel(); pd = pd.getOuterClass()) {
104+ // The inner classes specification states that the name of
105+ // a private field containing a reference to the outermost
106+ // enclosing instance is named "this$0". That outermost
107+ // enclosing instance is always the innermost toplevel class.
108+ depth += 1;
109+ }
110+ // In this example, T1,T2,T3 are all top-level (static),
111+ // while I4,I5,I6,I7 are all inner. Each of the inner classes
112+ // will have a single up-level "this$N" reference to the next
113+ // class out. Only the outermost "this$0" will refer to a
114+ // top-level class, T3.
115+ //
116+ // class T1 {
117+ // static class T2 {
118+ // static class T3 {
119+ // class I4 {
120+ // class I5 {
121+ // class I6 {
122+ // // at this point we have these fields in various places:
123+ // // I4 this$0; I5 this$1; I6 this$2;
124+ // }
125+ // }
126+ // class I7 {
127+ // // I4 this$0; I7 this$1;
128+ // }
129+ // }
130+ // }
131+ // }
132+ // }
133+ valName = Identifier.lookup(prefixThis + depth);
134+ } else {
135+ valName = Identifier.lookup(prefixVal + target.getName());
136+ }
137+
138+ // Make reasonably certain that valName is unique to this client.
139+ // (This check can be fooled by malicious naming of explicit
140+ // constructor arguments, or of inherited fields.)
141+ Identifier base = valName;
142+ int tick = 0;
143+ while (true) {
144+ boolean failed = (client.getFirstMatch(valName) != null);
145+ for (UplevelReference r = client.getReferences();
146+ r != null; r = r.next) {
147+ if (r.target.getName().equals(valName)) {
148+ failed = true;
149+ }
150+ }
151+ if (!failed) {
152+ break;
153+ }
154+ // try another name
155+ valName = Identifier.lookup(base + "$" + (++tick));
156+ }
157+
158+ // Build the constructor argument.
159+ // Like "this", it wil be shared equally by all constructors of client.
160+ localArgument = new LocalMember(target.getWhere(),
161+ client,
162+ M_FINAL | M_SYNTHETIC,
163+ target.getType(),
164+ valName);
165+ }
166+
167+ /**
168+ * Insert self into a list of references.
169+ * Maintain "isEarlierThan" as an invariant of the list.
170+ * This is important (a) to maximize stability of signatures,
171+ * and (b) to allow uplevel "this" parameters to come at the
172+ * front of every argument list they appear in.
173+ */
174+ public UplevelReference insertInto(UplevelReference references) {
175+ if (references == null || isEarlierThan(references)) {
176+ next = references;
177+ return this;
178+ } else {
179+ UplevelReference prev = references;
180+ while (!(prev.next == null || isEarlierThan(prev.next))) {
181+ prev = prev.next;
182+ }
183+ next = prev.next;
184+ prev.next = this;
185+ return references;
186+ }
187+ }
188+
189+ /**
190+ * Tells if self precedes the other in the canonical ordering.
191+ */
192+ public final boolean isEarlierThan(UplevelReference other) {
193+ // Outer fields always come first.
194+ if (isClientOuterField()) {
195+ return true;
196+ } else if (other.isClientOuterField()) {
197+ return false;
198+ }
199+
200+ // Now it doesn't matter what the order is; use string comparison.
201+ LocalMember target2 = other.target;
202+ Identifier name = target.getName();
203+ Identifier name2 = target2.getName();
204+ int cmp = name.toString().compareTo(name2.toString());
205+ if (cmp != 0) {
206+ return cmp < 0;
207+ }
208+ Identifier cname = target.getClassDefinition().getName();
209+ Identifier cname2 = target2.getClassDefinition().getName();
210+ int ccmp = cname.toString().compareTo(cname2.toString());
211+ return ccmp < 0;
212+ }
213+
214+ /**
215+ * the target of this reference
216+ */
217+ public final LocalMember getTarget() {
218+ return target;
219+ }
220+
221+ /**
222+ * the local argument for this reference
223+ */
224+ public final LocalMember getLocalArgument() {
225+ return localArgument;
226+ }
227+
228+ /**
229+ * the field allocated in the client for this reference
230+ */
231+ public final MemberDefinition getLocalField() {
232+ return localField;
233+ }
234+
235+ /**
236+ * Get the local field, creating one if necessary.
237+ * The client class must not be frozen.
238+ */
239+ public final MemberDefinition getLocalField(Environment env) {
240+ if (localField == null) {
241+ makeLocalField(env);
242+ }
243+ return localField;
244+ }
245+
246+ /**
247+ * the client class
248+ */
249+ public final ClassDefinition getClient() {
250+ return client;
251+ }
252+
253+ /**
254+ * the next reference in the client's list
255+ */
256+ public final UplevelReference getNext() {
257+ return next;
258+ }
259+
260+ /**
261+ * Tell if this uplevel reference is the up-level "this" pointer
262+ * of an inner class. Such references are treated differently
263+ * than others, because they affect constructor calls across
264+ * compilation units.
265+ */
266+ public boolean isClientOuterField() {
267+ MemberDefinition outerf = client.findOuterMember();
268+ return (outerf != null) && (localField == outerf);
269+ }
270+
271+ /**
272+ * Tell if my local argument is directly available in this context.
273+ * If not, the uplevel reference will have to be via a class field.
274+ * <p>
275+ * This must be called in a context which is local
276+ * to the client of the uplevel reference.
277+ */
278+ public boolean localArgumentAvailable(Environment env, Context ctx) {
279+ MemberDefinition reff = ctx.field;
280+ if (reff.getClassDefinition() != client) {
281+ throw new CompilerError("localArgumentAvailable");
282+ }
283+ return ( reff.isConstructor()
284+ || reff.isVariable()
285+ || reff.isInitializer() );
286+ }
287+
288+ /**
289+ * Process an uplevel reference.
290+ * The only decision to make at this point is whether
291+ * to build a "localField" instance variable, which
292+ * is done (lazily) when localArgumentAvailable() proves false.
293+ */
294+ public void noteReference(Environment env, Context ctx) {
295+ if (localField == null && !localArgumentAvailable(env, ctx)) {
296+ // We need an instance variable unless client is a constructor.
297+ makeLocalField(env);
298+ }
299+ }
300+
301+ private void makeLocalField(Environment env) {
302+ // Cannot alter decisions like this one at a late date.
303+ client.referencesMustNotBeFrozen();
304+ int mod = M_PRIVATE | M_FINAL | M_SYNTHETIC;
305+ localField = env.makeMemberDefinition(env,
306+ localArgument.getWhere(),
307+ client, null,
308+ mod,
309+ localArgument.getType(),
310+ localArgument.getName(),
311+ null, null, null);
312+ }
313+
314+ /**
315+ * Assuming noteReference() is all taken care of,
316+ * build an uplevel reference.
317+ * <p>
318+ * This must be called in a context which is local
319+ * to the client of the uplevel reference.
320+ */
321+ public Expression makeLocalReference(Environment env, Context ctx) {
322+ if (ctx.field.getClassDefinition() != client) {
323+ throw new CompilerError("makeLocalReference");
324+ }
325+ if (localArgumentAvailable(env, ctx)) {
326+ return new IdentifierExpression(0, localArgument);
327+ } else {
328+ return makeFieldReference(env, ctx);
329+ }
330+ }
331+
332+ /**
333+ * As with makeLocalReference(), build a locally-usable reference.
334+ * Ignore the availability of local arguments; always use a class field.
335+ */
336+ public Expression makeFieldReference(Environment env, Context ctx) {
337+ Expression e = ctx.findOuterLink(env, 0, localField);
338+ return new FieldExpression(0, e, localField);
339+ }
340+
341+ /**
342+ * During the inline phase, call this on a list of references
343+ * for which the code phase will later emit arguments.
344+ * It will make sure that any "double-uplevel" values
345+ * needed by the callee are also present at the call site.
346+ * <p>
347+ * If any reference is a "ClientOuterField", it is skipped
348+ * by this method (and by willCodeArguments). This is because
349+ */
350+ public void willCodeArguments(Environment env, Context ctx) {
351+ if (!isClientOuterField()) {
352+ ctx.noteReference(env, target);
353+ }
354+
355+ if (next != null) {
356+ next.willCodeArguments(env, ctx);
357+ }
358+ }
359+
360+ /**
361+ * Code is being generated for a call to a constructor of
362+ * the client class. Push an argument for the constructor.
363+ */
364+ public void codeArguments(Environment env, Context ctx, Assembler asm,
365+ long where, MemberDefinition conField) {
366+ if (!isClientOuterField()) {
367+ Expression e = ctx.makeReference(env, target);
368+ e.codeValue(env, ctx, asm);
369+ }
370+
371+ if (next != null) {
372+ next.codeArguments(env, ctx, asm, where, conField);
373+ }
374+ }
375+
376+ /**
377+ * Code is being generated for a constructor of the client class.
378+ * Emit code which initializes the instance.
379+ */
380+ public void codeInitialization(Environment env, Context ctx, Assembler asm,
381+ long where, MemberDefinition conField) {
382+ // If the reference is a clientOuterField, then the initialization
383+ // code is generated in MethodExpression.makeVarInits().
384+ // (Fix for bug 4075063.)
385+ if (localField != null && !isClientOuterField()) {
386+ Expression e = ctx.makeReference(env, target);
387+ Expression f = makeFieldReference(env, ctx);
388+ e = new AssignExpression(e.getWhere(), f, e);
389+ e.type = localField.getType();
390+ e.code(env, ctx, asm);
391+ }
392+
393+ if (next != null) {
394+ next.codeInitialization(env, ctx, asm, where, conField);
395+ }
396+ }
397+
398+ public String toString() {
399+ return "[" + localArgument + " in " + client + "]";
400+ }
401+}