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

Unified · Split

java/pkg/sun/tools/tree/NewInstanceExpression.java+545−0
@@ -0,0 +1,545 @@
1+/*
2+ * Copyright (c) 1994, 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.asm.Assembler;
30+import java.util.Hashtable;
31+
32+/**
33+ * WARNING: The contents of this source file are not part of any
34+ * supported API. Code that depends on them does so at its own risk:
35+ * they are subject to change or removal without notice.
36+ */
37+public
38+class NewInstanceExpression extends NaryExpression {
39+ MemberDefinition field;
40+ Expression outerArg;
41+ ClassDefinition body;
42+
43+ // Access method for constructor, if needed.
44+ MemberDefinition implMethod = null;
45+
46+ /**
47+ * Constructor
48+ */
49+ public NewInstanceExpression(long where, Expression right, Expression args[]) {
50+ super(NEWINSTANCE, where, Type.tError, right, args);
51+ }
52+ public NewInstanceExpression(long where, Expression right,
53+ Expression args[],
54+ Expression outerArg, ClassDefinition body) {
55+ this(where, right, args);
56+ this.outerArg = outerArg;
57+ this.body = body;
58+ }
59+
60+ /**
61+ * From the "new" in an expression of the form outer.new InnerCls(...),
62+ * return the "outer" expression, or null if there is none.
63+ */
64+ public Expression getOuterArg() {
65+ return outerArg;
66+ }
67+
68+ int precedence() {
69+ return 100;
70+ }
71+
72+ public Expression order() {
73+ // act like a method or field reference expression:
74+ if (outerArg != null && opPrecedence[FIELD] > outerArg.precedence()) {
75+ UnaryExpression e = (UnaryExpression)outerArg;
76+ outerArg = e.right;
77+ e.right = order();
78+ return e;
79+ }
80+ return this;
81+ }
82+
83+ /**
84+ * Check expression type
85+ */
86+ public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) {
87+ // What type?
88+ ClassDefinition def = null;
89+
90+ Expression alreadyChecked = null;
91+
92+ try {
93+ if (outerArg != null) {
94+ vset = outerArg.checkValue(env, ctx, vset, exp);
95+
96+ // Remember the expression that we already checked
97+ // so that we don't attempt to check it again when
98+ // it appears as an argument to the constructor.
99+ // Fix for 4030426.
100+ alreadyChecked = outerArg;
101+
102+ // Check outerArg and the type name together.
103+ Identifier typeName = FieldExpression.toIdentifier(right);
104+
105+ // According to the inner classes spec, the type name in a
106+ // qualified 'new' expression must be a single identifier.
107+ if (typeName != null && typeName.isQualified()) {
108+ env.error(where, "unqualified.name.required", typeName);
109+ }
110+
111+ if (typeName == null || !outerArg.type.isType(TC_CLASS)) {
112+ if (!outerArg.type.isType(TC_ERROR)) {
113+ env.error(where, "invalid.field.reference",
114+ idNew, outerArg.type);
115+ }
116+ outerArg = null;
117+ } else {
118+ // Don't perform checks on components of qualified name
119+ // ('getQualifiedClassDefinition'), because a qualified
120+ // name is illegal in this context, and will have previously
121+ // been reported as an error.
122+ ClassDefinition oc = env.getClassDefinition(outerArg.type);
123+ Identifier nm = oc.resolveInnerClass(env, typeName);
124+ right = new TypeExpression(right.where, Type.tClass(nm));
125+ // Check access directly, since we're not calling toType().
126+ env.resolve(right.where, ctx.field.getClassDefinition(),
127+ right.type);
128+ // and fall through to env.getClassDefinition() below
129+ }
130+ }
131+
132+ if (!(right instanceof TypeExpression)) {
133+ // The call to 'toType' should perform component access checks.
134+ right = new TypeExpression(right.where, right.toType(env, ctx));
135+ }
136+
137+ if (right.type.isType(TC_CLASS))
138+ def = env.getClassDefinition(right.type);
139+ } catch (AmbiguousClass ee) {
140+ env.error(where, "ambig.class", ee.name1, ee.name2);
141+ } catch (ClassNotFound ee) {
142+ env.error(where, "class.not.found", ee.name, ctx.field);
143+ }
144+
145+ Type t = right.type;
146+ boolean hasErrors = t.isType(TC_ERROR);
147+
148+ if (!t.isType(TC_CLASS)) {
149+ if (!hasErrors) {
150+ env.error(where, "invalid.arg.type", t, opNames[op]);
151+ hasErrors = true;
152+ }
153+ }
154+
155+ // If we failed to find a class or a class was ambiguous, def
156+ // may be null. Bail out. This allows us to report multiple
157+ // unfound or ambiguous classes rather than tripping over an
158+ // internal compiler error.
159+ if (def == null) {
160+ type = Type.tError;
161+ return vset;
162+ }
163+
164+ // Add an extra argument, maybe.
165+ Expression args[] = this.args;
166+ args = NewInstanceExpression.
167+ insertOuterLink(env, ctx, where, def, outerArg, args);
168+ if (args.length > this.args.length)
169+ outerArg = args[0]; // recopy the checked arg
170+ else if (outerArg != null)
171+ // else set it to void (maybe it has a side-effect)
172+ outerArg = new CommaExpression(outerArg.where, outerArg, null);
173+
174+ // Compose a list of argument types
175+ Type argTypes[] = new Type[args.length];
176+
177+ for (int i = 0 ; i < args.length ; i++) {
178+ // Don't check 'outerArg' again. Fix for 4030426.
179+ if (args[i] != alreadyChecked) {
180+ vset = args[i].checkValue(env, ctx, vset, exp);
181+ }
182+ argTypes[i] = args[i].type;
183+ hasErrors = hasErrors || argTypes[i].isType(TC_ERROR);
184+ }
185+
186+ try {
187+ // Check if there are any type errors in the arguments
188+ if (hasErrors) {
189+ type = Type.tError;
190+ return vset;
191+ }
192+
193+
194+ // Get the source class that this declaration appears in.
195+ ClassDefinition sourceClass = ctx.field.getClassDefinition();
196+
197+ ClassDeclaration c = env.getClassDeclaration(t);
198+
199+ // If this is an anonymous class, handle it specially now.
200+ if (body != null) {
201+ // The current package.
202+ Identifier packageName = sourceClass.getName().getQualifier();
203+
204+ // This is an anonymous class.
205+ ClassDefinition superDef = null;
206+ if (def.isInterface()) {
207+ // For interfaces, our superclass is java.lang.Object.
208+ // We could just assume that java.lang.Object has
209+ // one constructor with no arguments in the code
210+ // that follows, but we don't. This way, if Object
211+ // grows a new constructor (unlikely) then the
212+ // compiler should handle it.
213+ superDef = env.getClassDefinition(idJavaLangObject);
214+ } else {
215+ // Otherwise, def is actually our superclass.
216+ superDef = def;
217+ }
218+ // Try to find a matching constructor in our superclass.
219+ MemberDefinition constructor =
220+ superDef.matchAnonConstructor(env, packageName, argTypes);
221+ if (constructor != null) {
222+ // We've found one. Process the body.
223+ //
224+ // Note that we are passing in the constructors' argument
225+ // types, rather than the argument types of the actual
226+ // expressions, to checkLocalClass(). Previously,
227+ // the expression types were passed in. This could
228+ // lead to trouble when one of the argument types was
229+ // the special internal type tNull. (bug 4054689).
230+ if (tracing)
231+ env.dtEvent(
232+ "NewInstanceExpression.checkValue: ANON CLASS " +
233+ body + " SUPER " + def);
234+ vset = body.checkLocalClass(env, ctx, vset,
235+ def, args,
236+ constructor.getType()
237+ .getArgumentTypes());
238+
239+ // Set t to be the true type of this expression.
240+ // (bug 4102056).
241+ t = body.getClassDeclaration().getType();
242+
243+ def = body;
244+ }
245+ } else {
246+ // Check if it is an interface
247+ if (def.isInterface()) {
248+ env.error(where, "new.intf", c);
249+ return vset;
250+ }
251+
252+ // Check for abstract class
253+ if (def.mustBeAbstract(env)) {
254+ env.error(where, "new.abstract", c);
255+ return vset;
256+ }
257+ }
258+
259+ // Get the constructor that the "new" expression should call.
260+ field = def.matchMethod(env, sourceClass, idInit, argTypes);
261+
262+ // Report an error if there is no matching constructor.
263+ if (field == null) {
264+ MemberDefinition anyInit = def.findAnyMethod(env, idInit);
265+ if (anyInit != null &&
266+ new MethodExpression(where, right, anyInit, args)
267+ .diagnoseMismatch(env, args, argTypes))
268+ return vset;
269+ String sig = c.getName().getName().toString();
270+ sig = Type.tMethod(Type.tError, argTypes).typeString(sig, false, false);
271+ env.error(where, "unmatched.constr", sig, c);
272+ return vset;
273+ }
274+
275+ if (field.isPrivate()) {
276+ ClassDefinition cdef = field.getClassDefinition();
277+ if (cdef != sourceClass) {
278+ // Use access method.
279+ implMethod = cdef.getAccessMember(env, ctx, field, false);
280+ }
281+ }
282+
283+ // Check for abstract anonymous class
284+ if (def.mustBeAbstract(env)) {
285+ env.error(where, "new.abstract", c);
286+ return vset;
287+ }
288+
289+ if (field.reportDeprecated(env)) {
290+ env.error(where, "warn.constr.is.deprecated",
291+ field, field.getClassDefinition());
292+ }
293+
294+ // According to JLS 6.6.2, a protected constructor may be accessed
295+ // by a class instance creation expression only from within the
296+ // package in which it is defined.
297+ if (field.isProtected() &&
298+ !(sourceClass.getName().getQualifier().equals(
299+ field.getClassDeclaration().getName().getQualifier()))) {
300+ env.error(where, "invalid.protected.constructor.use",
301+ sourceClass);
302+ }
303+
304+ } catch (ClassNotFound ee) {
305+ env.error(where, "class.not.found", ee.name, opNames[op]);
306+ return vset;
307+
308+ } catch (AmbiguousMember ee) {
309+ env.error(where, "ambig.constr", ee.field1, ee.field2);
310+ return vset;
311+ }
312+
313+ // Cast arguments
314+ argTypes = field.getType().getArgumentTypes();
315+ for (int i = 0 ; i < args.length ; i++) {
316+ args[i] = convert(env, ctx, argTypes[i], args[i]);
317+ }
318+ if (args.length > this.args.length) {
319+ outerArg = args[0]; // recopy the checked arg
320+ // maintain an accurate tree
321+ for (int i = 1 ; i < args.length ; i++) {
322+ this.args[i-1] = args[i];
323+ }
324+ }
325+
326+ // Throw the declared exceptions.
327+ ClassDeclaration exceptions[] = field.getExceptions(env);
328+ for (int i = 0 ; i < exceptions.length ; i++) {
329+ if (exp.get(exceptions[i]) == null) {
330+ exp.put(exceptions[i], this);
331+ }
332+ }
333+
334+ type = t;
335+
336+ return vset;
337+ }
338+
339+ /**
340+ * Given a list of arguments for a constructor,
341+ * return a possibly modified list which includes the hidden
342+ * argument which initializes the uplevel self pointer.
343+ * @arg def the class which perhaps contains an outer link.
344+ * @arg outerArg if non-null, an explicit location in which to construct.
345+ */
346+ public static Expression[] insertOuterLink(Environment env, Context ctx,
347+ long where, ClassDefinition def,
348+ Expression outerArg,
349+ Expression args[]) {
350+ if (!def.isTopLevel() && !def.isLocal()) {
351+ Expression args2[] = new Expression[1+args.length];
352+ System.arraycopy(args, 0, args2, 1, args.length);
353+ try {
354+ if (outerArg == null)
355+ outerArg = ctx.findOuterLink(env, where,
356+ def.findAnyMethod(env, idInit));
357+ } catch (ClassNotFound e) {
358+ // die somewhere else
359+ }
360+ args2[0] = outerArg;
361+ args = args2;
362+ }
363+ return args;
364+ }
365+
366+ /**
367+ * Check void expression
368+ */
369+ public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
370+ return checkValue(env, ctx, vset, exp);
371+ }
372+
373+ /**
374+ * Inline
375+ */
376+ final int MAXINLINECOST = Statement.MAXINLINECOST;
377+
378+ public Expression copyInline(Context ctx) {
379+ NewInstanceExpression e = (NewInstanceExpression)super.copyInline(ctx);
380+ if (outerArg != null) {
381+ e.outerArg = outerArg.copyInline(ctx);
382+ }
383+ return e;
384+ }
385+
386+ Expression inlineNewInstance(Environment env, Context ctx, Statement s) {
387+ if (env.dump()) {
388+ System.out.println("INLINE NEW INSTANCE " + field + " in " + ctx.field);
389+ }
390+ LocalMember v[] = LocalMember.copyArguments(ctx, field);
391+ Statement body[] = new Statement[v.length + 2];
392+
393+ int o = 1;
394+ if (outerArg != null && !outerArg.type.isType(TC_VOID)) {
395+ o = 2;
396+ body[1] = new VarDeclarationStatement(where, v[1], outerArg);
397+ } else if (outerArg != null) {
398+ body[0] = new ExpressionStatement(where, outerArg);
399+ }
400+ for (int i = 0 ; i < args.length ; i++) {
401+ body[i+o] = new VarDeclarationStatement(where, v[i+o], args[i]);
402+ }
403+ //System.out.print("BEFORE:"); s.print(System.out); System.out.println();
404+ body[body.length - 1] = (s != null) ? s.copyInline(ctx, false) : null;
405+ //System.out.print("COPY:"); body[body.length - 1].print(System.out); System.out.println();
406+ //System.out.print("AFTER:"); s.print(System.out); System.out.println();
407+ LocalMember.doneWithArguments(ctx, v);
408+
409+ return new InlineNewInstanceExpression(where, type, field, new CompoundStatement(where, body)).inline(env, ctx);
410+ }
411+
412+ public Expression inline(Environment env, Context ctx) {
413+ return inlineValue(env, ctx);
414+ }
415+ public Expression inlineValue(Environment env, Context ctx) {
416+ if (body != null) {
417+ body.inlineLocalClass(env);
418+ }
419+ ClassDefinition refc = field.getClassDefinition();
420+ UplevelReference r = refc.getReferencesFrozen();
421+ if (r != null) {
422+ r.willCodeArguments(env, ctx);
423+ }
424+ //right = right.inlineValue(env, ctx);
425+
426+ try {
427+ if (outerArg != null) {
428+ if (outerArg.type.isType(TC_VOID))
429+ outerArg = outerArg.inline(env, ctx);
430+ else
431+ outerArg = outerArg.inlineValue(env, ctx);
432+ }
433+ for (int i = 0 ; i < args.length ; i++) {
434+ args[i] = args[i].inlineValue(env, ctx);
435+ }
436+ // This 'false' that fy put in is inexplicable to me
437+ // the decision to not inline new instance expressions
438+ // should be revisited. - dps
439+ if (false && env.opt() && field.isInlineable(env, false) &&
440+ (!ctx.field.isInitializer()) && ctx.field.isMethod() &&
441+ (ctx.getInlineMemberContext(field) == null)) {
442+ Statement s = (Statement)field.getValue(env);
443+ if ((s == null)
444+ || (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST)) {
445+ return inlineNewInstance(env, ctx, s);
446+ }
447+ }
448+ } catch (ClassNotFound e) {
449+ throw new CompilerError(e);
450+ }
451+ if (outerArg != null && outerArg.type.isType(TC_VOID)) {
452+ Expression e = outerArg;
453+ outerArg = null;
454+ return new CommaExpression(where, e, this);
455+ }
456+ return this;
457+ }
458+
459+ public int costInline(int thresh, Environment env, Context ctx) {
460+ if (body != null) {
461+ return thresh; // don't copy classes...
462+ }
463+ if (ctx == null) {
464+ return 2 + super.costInline(thresh, env, ctx);
465+ }
466+ // sourceClass is the current class trying to inline this method
467+ ClassDefinition sourceClass = ctx.field.getClassDefinition();
468+ try {
469+ // We only allow the inlining if the current class can access
470+ // the field and the field's class;
471+ if ( sourceClass.permitInlinedAccess(env, field.getClassDeclaration())
472+ && sourceClass.permitInlinedAccess(env, field)) {
473+ return 2 + super.costInline(thresh, env, ctx);
474+ }
475+ } catch (ClassNotFound e) {
476+ }
477+ return thresh;
478+ }
479+
480+
481+ /**
482+ * Code
483+ */
484+ public void code(Environment env, Context ctx, Assembler asm) {
485+ codeCommon(env, ctx, asm, false);
486+ }
487+ public void codeValue(Environment env, Context ctx, Assembler asm) {
488+ codeCommon(env, ctx, asm, true);
489+ }
490+ private void codeCommon(Environment env, Context ctx, Assembler asm,
491+ boolean forValue) {
492+ asm.add(where, opc_new, field.getClassDeclaration());
493+ if (forValue) {
494+ asm.add(where, opc_dup);
495+ }
496+
497+ ClassDefinition refc = field.getClassDefinition();
498+ UplevelReference r = refc.getReferencesFrozen();
499+
500+ if (r != null) {
501+ r.codeArguments(env, ctx, asm, where, field);
502+ }
503+
504+ if (outerArg != null) {
505+ outerArg.codeValue(env, ctx, asm);
506+ switch (outerArg.op) {
507+ case THIS:
508+ case SUPER:
509+ case NEW:
510+ // guaranteed non-null
511+ break;
512+ case FIELD: {
513+ MemberDefinition f = ((FieldExpression)outerArg).field;
514+ if (f != null && f.isNeverNull()) {
515+ break;
516+ }
517+ // else fall through:
518+ }
519+ default:
520+ // Test for nullity by invoking some trivial operation
521+ // that can throw a NullPointerException.
522+ try {
523+ ClassDefinition c = env.getClassDefinition(idJavaLangObject);
524+ MemberDefinition getc = c.getFirstMatch(idGetClass);
525+ asm.add(where, opc_dup);
526+ asm.add(where, opc_invokevirtual, getc);
527+ asm.add(where, opc_pop);
528+ } catch (ClassNotFound e) {
529+ }
530+ }
531+ }
532+
533+ if (implMethod != null) {
534+ // Constructor call will be via an access method.
535+ // Pass 'null' as the value of the dummy argument.
536+ asm.add(where, opc_aconst_null);
537+ }
538+
539+ for (int i = 0 ; i < args.length ; i++) {
540+ args[i].codeValue(env, ctx, asm);
541+ }
542+ asm.add(where, opc_invokespecial,
543+ ((implMethod != null) ? implMethod : field));
544+ }
545+}