View Javadoc
1   /*
2    * Copyright (c) 1994, 2004, 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.Label;
30  import sun.tools.asm.Assembler;
31  import java.io.PrintStream;
32  import java.util.Hashtable;
33  
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  public
40  class Expression extends Node {
41      Type type;
42  
43      /**
44       * Constructor
45       */
46      Expression(int op, long where, Type type) {
47          super(op, where);
48          this.type = type;
49      }
50  
51      /**
52       * Type checking may assign a more complex implementation
53       * to an innocuous-looking expression (like an identifier).
54       * Return that implementation, or the original expression itself
55       * if there is no special implementation.
56       * <p>
57       * This appears at present to be dead code, and is not called
58       * from within javac.  Access to the implementation generally
59       * occurs within the same class, and thus uses the underlying
60       * field directly.
61       */
62      public Expression getImplementation() {
63          return this;
64      }
65  
66      public Type getType() {
67          return type;
68      }
69  
70      /**
71       * Return the precedence of the operator
72       */
73      int precedence() {
74          return (op < opPrecedence.length) ? opPrecedence[op] : 100;
75      }
76  
77      /**
78       * Order the expression based on precedence
79       */
80      public Expression order() {
81          return this;
82      }
83  
84      /**
85       * Return true if constant, according to JLS 15.27.
86       * A constant expression must inline away to a literal constant.
87       */
88      public boolean isConstant() {
89          return false;
90      }
91  
92      /**
93       * Return the constant value.
94       */
95      public Object getValue() {
96          return null;
97      }
98  
99      /**
100      * Check if the expression is known to be equal to a given value.
101      * Returns false for any expression other than a literal constant,
102      * thus should be called only after simplification (inlining) has
103      * been performed.
104      */
105     public boolean equals(int i) {
106         return false;
107     }
108     public boolean equals(boolean b) {
109         return false;
110     }
111     public boolean equals(Identifier id) {
112         return false;
113     }
114     public boolean equals(String s) {
115         return false;
116     }
117 
118     /**
119      * Check if the expression must be a null reference.
120      */
121     public boolean isNull() {
122         return false;
123     }
124 
125     /**
126      * Check if the expression cannot be a null reference.
127      */
128     public boolean isNonNull() {
129         return false;
130     }
131 
132     /**
133      * Check if the expression is equal to its default static value
134      */
135     public boolean equalsDefault() {
136         return false;
137     }
138 
139 
140     /**
141      * Convert an expresion to a type
142      */
143     Type toType(Environment env, Context ctx) {
144         env.error(where, "invalid.type.expr");
145         return Type.tError;
146     }
147 
148     /**
149      * Convert an expresion to a type in a context where a qualified
150      * type name is expected, e.g., in the prefix of a qualified type
151      * name.
152      */
153     /*-----------------------------------------------------*
154     Type toQualifiedType(Environment env, Context ctx) {
155         env.error(where, "invalid.type.expr");
156         return Type.tError;
157     }
158     *-----------------------------------------------------*/
159 
160     /**
161      * See if this expression fits in the given type.
162      * This is useful because some larger numbers fit into
163      * smaller types.
164      * <p>
165      * If it is an "int" constant expression, inline it, if necessary,
166      * to examine its numerical value.  See JLS 5.2 and 15.24.
167      */
168     public boolean fitsType(Environment env, Context ctx, Type t) {
169         try {
170             if (env.isMoreSpecific(this.type, t)) {
171                 return true;
172             }
173             if (this.type.isType(TC_INT) && this.isConstant() && ctx != null) {
174                 // Tentative inlining is harmless for constant expressions.
175                 Expression n = this.inlineValue(env, ctx);
176                 if (n != this && n instanceof ConstantExpression) {
177                     return n.fitsType(env, ctx, t);
178                 }
179             }
180             return false;
181         } catch (ClassNotFound e) {
182             return false;
183         }
184     }
185 
186     /** @deprecated (for backward compatibility) */
187     @Deprecated
188     public boolean fitsType(Environment env, Type t) {
189         return fitsType(env, (Context) null, t);
190     }
191 
192     /**
193      * Check an expression
194      */
195     public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) {
196         return vset;
197     }
198     public Vset checkInitializer(Environment env, Context ctx, Vset vset, Type t, Hashtable exp) {
199         return checkValue(env, ctx, vset, exp);
200     }
201     public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
202         throw new CompilerError("check failed");
203     }
204 
205     public Vset checkLHS(Environment env, Context ctx,
206                             Vset vset, Hashtable exp) {
207         env.error(where, "invalid.lhs.assignment");
208         type = Type.tError;
209         return vset;
210     }
211 
212     /**
213      * Return a <code>FieldUpdater</code> object to be used in updating the
214      * value of the location denoted by <code>this</code>, which must be an
215      * expression suitable for the left-hand side of an assignment.
216      * This is used for implementing assignments to private fields for which
217      * an access method is required.  Returns null if no access method is
218      * needed, in which case the assignment is handled in the usual way, by
219      * direct access.  Only simple assignment expressions are handled here
220      * Assignment operators and pre/post increment/decrement operators are
221      * are handled by 'getUpdater' below.
222      * <p>
223      * Called during the checking phase.
224      */
225 
226     public FieldUpdater getAssigner(Environment env, Context ctx) {
227         throw new CompilerError("getAssigner lhs");
228     }
229 
230     /**
231      * Return a <code>FieldUpdater</code> object to be used in updating the value of the
232      * location denoted by <code>this</code>, which must be an expression suitable for the
233      * left-hand side of an assignment.  This is used for implementing the assignment
234      * operators and the increment/decrement operators on private fields that require an
235      * access method, e.g., uplevel from an inner class.  Returns null if no access method
236      * is needed.
237      * <p>
238      * Called during the checking phase.
239      */
240 
241     public FieldUpdater getUpdater(Environment env, Context ctx) {
242         throw new CompilerError("getUpdater lhs");
243     }
244 
245     public Vset checkAssignOp(Environment env, Context ctx,
246                               Vset vset, Hashtable exp, Expression outside) {
247         if (outside instanceof IncDecExpression)
248             env.error(where, "invalid.arg", opNames[outside.op]);
249         else
250             env.error(where, "invalid.lhs.assignment");
251         type = Type.tError;
252         return vset;
253     }
254 
255     /**
256      * Check something that might be an AmbiguousName (refman 6.5.2).
257      * A string of dot-separated identifiers might be, in order of preference:
258      * <nl>
259      * <li> a variable name followed by fields or types
260      * <li> a type name followed by fields or types
261      * <li> a package name followed a type and then fields or types
262      * </nl>
263      * If a type name is found, it rewrites itself as a <tt>TypeExpression</tt>.
264      * If a node decides it can only be a package prefix, it sets its
265      * type to <tt>Type.tPackage</tt>.  The caller must detect this
266      * and act appropriately to verify the full package name.
267      * @arg loc the expression containing the ambiguous expression
268      */
269     public Vset checkAmbigName(Environment env, Context ctx, Vset vset, Hashtable exp,
270                                UnaryExpression loc) {
271         return checkValue(env, ctx, vset, exp);
272     }
273 
274     /**
275      * Check a condition.  Return a ConditionVars(), which indicates when
276      * which variables are set if the condition is true, and which are set if
277      * the condition is false.
278      */
279     public ConditionVars checkCondition(Environment env, Context ctx,
280                                         Vset vset, Hashtable exp) {
281         ConditionVars cvars = new ConditionVars();
282         checkCondition(env, ctx, vset, exp, cvars);
283         return cvars;
284     }
285 
286     /*
287      * Check a condition.
288      *
289      * cvars is modified so that
290      *    cvar.vsTrue indicates variables with a known value if result = true
291      *    cvars.vsFalse indicates variables with a known value if !result
292      *
293      * The default action is to simply call checkValue on the expression, and
294      * to see both vsTrue and vsFalse to the result.
295      */
296 
297     public void checkCondition(Environment env, Context ctx,
298                                Vset vset, Hashtable exp, ConditionVars cvars) {
299         cvars.vsTrue = cvars.vsFalse = checkValue(env, ctx, vset, exp);
300         // unshare side effects:
301         cvars.vsFalse = cvars.vsFalse.copy();
302     }
303 
304     /**
305      * Evaluate.
306      *
307      * Attempt to compute the value of an expression node.  If all operands are
308      * literal constants of the same kind (e.g., IntegerExpression nodes), a
309      * new constant node of the proper type is returned representing the value
310      * as computed at compile-time.  Otherwise, the original node 'this' is
311      * returned.
312      */
313     Expression eval() {
314         return this;
315     }
316 
317     /**
318      * Simplify.
319      *
320      * Attempt to simplify an expression node by returning a semantically-
321      * equivalent expression that is presumably less costly to execute.  There
322      * is some overlap with the intent of 'eval', as compile-time evaluation of
323      * conditional expressions and the short-circuit boolean operators is
324      * performed here.  Other simplifications include logical identities
325      * involving logical negation and comparisons.  If no simplification is
326      * possible, the original node 'this' is returned.  It is assumed that the
327      * children of the node have previously been recursively simplified and
328      * evaluated.  A result of 'null' indicates that the expression may be
329      * elided entirely.
330      */
331     Expression simplify() {
332         return this;
333     }
334 
335     /**
336      * Inline.
337      *
338      * Recursively simplify each child of an expression node, destructively
339      * replacing the child with the simplified result.  Also attempts to
340      * simplify the current node 'this', and returns the simplified result.
341      *
342      * The name 'inline' is somthing of a misnomer, as these methods are
343      * responsible for compile-time expression simplification in general.
344      * The 'eval' and 'simplify' methods apply to a single expression node
345      * only -- it is 'inline' and 'inlineValue' that drive the simplification
346      * of entire expressions.
347      */
348     public Expression inline(Environment env, Context ctx) {
349         return null;
350     }
351     public Expression inlineValue(Environment env, Context ctx) {
352         return this;
353     }
354 
355     /**
356      * Attempt to evaluate this expression.  If this expression
357      * yields a value, append it to the StringBuffer `buffer'.
358      * If this expression cannot be evaluated at this time (for
359      * example if it contains a division by zero, a non-constant
360      * subexpression, or a subexpression which "refuses" to evaluate)
361      * then return `null' to indicate failure.
362      *
363      * It is anticipated that this method will be called to evaluate
364      * concatenations of compile-time constant strings.  The call
365      * originates from AddExpression#inlineValue().
366      *
367      * See AddExpression#inlineValueSB() for detailed comments.
368      */
369     protected StringBuffer inlineValueSB(Environment env,
370                                          Context ctx,
371                                          StringBuffer buffer) {
372         Expression inlined = inlineValue(env, ctx);
373         Object val = inlined.getValue();
374 
375         if (val == null && !inlined.isNull()){
376             // This (supposedly constant) expression refuses to yield
377             // a value.  This can happen, in particular, when we are
378             // trying to evaluate a division by zero.  It can also
379             // happen in cases where isConstant() is able to classify
380             // expressions as constant that the compiler's inlining
381             // mechanisms aren't able to evaluate; this is rare,
382             // and all such cases that we have found so far
383             // (e.g. 4082814, 4106244) have been plugged up.
384             //
385             // We return a null to indicate that we have failed to
386             // evaluate the concatenation.
387             return null;
388         }
389 
390         // For boolean and character expressions, getValue() returns
391         // an Integer.  We need to take care, when appending the result
392         // of getValue(), that we preserve the type.
393         // Fix for 4103959, 4102672.
394         if (type == Type.tChar) {
395             buffer.append((char)((Integer)val).intValue());
396         } else if (type == Type.tBoolean) {
397             buffer.append(((Integer)val).intValue() != 0);
398         } else {
399             buffer.append(val);
400         }
401 
402         return buffer;
403     }
404 
405     public Expression inlineLHS(Environment env, Context ctx) {
406         return null;
407     }
408 
409     /**
410      * The cost of inlining this expression.
411      * This cost controls the inlining of methods, and does not determine
412      * the compile-time simplifications performed by 'inline' and friends.
413      */
414     public int costInline(int thresh, Environment env, Context ctx) {
415         return 1;
416     }
417 
418     /**
419      * Code
420      */
421     void codeBranch(Environment env, Context ctx, Assembler asm, Label lbl, boolean whenTrue) {
422         if (type.isType(TC_BOOLEAN)) {
423             codeValue(env, ctx, asm);
424             asm.add(where, whenTrue ? opc_ifne : opc_ifeq, lbl, whenTrue);
425         } else {
426             throw new CompilerError("codeBranch " + opNames[op]);
427         }
428     }
429     public void codeValue(Environment env, Context ctx, Assembler asm) {
430         if (type.isType(TC_BOOLEAN)) {
431             Label l1 = new Label();
432             Label l2 = new Label();
433 
434             codeBranch(env, ctx, asm, l1, true);
435             asm.add(true, where, opc_ldc, new Integer(0));
436             asm.add(true, where, opc_goto, l2);
437             asm.add(l1);
438             asm.add(true, where, opc_ldc, new Integer(1));
439             asm.add(l2);
440         } else {
441             throw new CompilerError("codeValue");
442         }
443     }
444     public void code(Environment env, Context ctx, Assembler asm) {
445         codeValue(env, ctx, asm);
446 
447         switch (type.getTypeCode()) {
448           case TC_VOID:
449             break;
450 
451           case TC_DOUBLE:
452           case TC_LONG:
453             asm.add(where, opc_pop2);
454             break;
455 
456           default:
457             asm.add(where, opc_pop);
458             break;
459         }
460     }
461     int codeLValue(Environment env, Context ctx, Assembler asm) {
462         print(System.out);
463         throw new CompilerError("invalid lhs");
464     }
465     void codeLoad(Environment env, Context ctx, Assembler asm) {
466         print(System.out);
467         throw new CompilerError("invalid load");
468     }
469     void codeStore(Environment env, Context ctx, Assembler asm) {
470         print(System.out);
471         throw new CompilerError("invalid store");
472     }
473 
474     /**
475      * Convert this expression to a string.
476      */
477     void ensureString(Environment env, Context ctx, Assembler asm)
478             throws ClassNotFound, AmbiguousMember
479     {
480         if (type == Type.tString && isNonNull()) {
481             return;
482         }
483         // Make sure it's a non-null string.
484         ClassDefinition sourceClass = ctx.field.getClassDefinition();
485         ClassDeclaration stClass = env.getClassDeclaration(Type.tString);
486         ClassDefinition stClsDef = stClass.getClassDefinition(env);
487         // FIX FOR 4071548
488         // We use 'String.valueOf' to do the conversion, in order to
489         // correctly handle null references and efficiently handle
490         // primitive types.  For reference types, we force the argument
491         // to be interpreted as of 'Object' type, thus avoiding the
492         // the special-case overloading of 'valueOf' for character arrays.
493         // This special treatment would conflict with JLS 15.17.1.1.
494         if (type.inMask(TM_REFERENCE)) {
495             // Reference type
496             if (type != Type.tString) {
497                 // Convert non-string object to string.  If object is
498                 // a string, we don't need to convert it, except in the
499                 // case that it is null, which is handled below.
500                 Type argType1[] = {Type.tObject};
501                 MemberDefinition f1 =
502                     stClsDef.matchMethod(env, sourceClass, idValueOf, argType1);
503                 asm.add(where, opc_invokestatic, f1);
504             }
505             // FIX FOR 4030173
506             // If the argument was null, then value is "null", but if the
507             // argument was not null, 'toString' was called and could have
508             // returned null.  We call 'valueOf' again to make sure that
509             // the result is a non-null string.  See JLS 15.17.1.1.  The
510             // approach taken here minimizes code size -- open code would
511             // be faster.  The 'toString' method for an array class cannot
512             // be overridden, thus we know that it will never return null.
513             if (!type.inMask(TM_ARRAY|TM_NULL)) {
514                 Type argType2[] = {Type.tString};
515                 MemberDefinition f2 =
516                     stClsDef.matchMethod(env, sourceClass, idValueOf, argType2);
517                 asm.add(where, opc_invokestatic, f2);
518             }
519         } else {
520             // Primitive type
521             Type argType[] = {type};
522             MemberDefinition f =
523                 stClsDef.matchMethod(env, sourceClass, idValueOf, argType);
524             asm.add(where, opc_invokestatic, f);
525         }
526     }
527 
528     /**
529      * Convert this expression to a string and append it to the string
530      * buffer on the top of the stack.
531      * If the needBuffer argument is true, the string buffer needs to be
532      * created, initialized, and pushed on the stack, first.
533      */
534     void codeAppend(Environment env, Context ctx, Assembler asm,
535                     ClassDeclaration sbClass, boolean needBuffer)
536             throws ClassNotFound, AmbiguousMember
537     {
538         ClassDefinition sourceClass = ctx.field.getClassDefinition();
539         ClassDefinition sbClsDef = sbClass.getClassDefinition(env);
540         MemberDefinition f;
541         if (needBuffer) {
542             // need to create the string buffer
543             asm.add(where, opc_new, sbClass); // create the class
544             asm.add(where, opc_dup);
545             if (equals("")) {
546                 // make an empty string buffer
547                 f = sbClsDef.matchMethod(env, sourceClass, idInit);
548             } else {
549                 // optimize by initializing the buffer with the string
550                 codeValue(env, ctx, asm);
551                 ensureString(env, ctx, asm);
552                 Type argType[] = {Type.tString};
553                 f = sbClsDef.matchMethod(env, sourceClass, idInit, argType);
554             }
555             asm.add(where, opc_invokespecial, f);
556         } else {
557             // append this item to the string buffer
558             codeValue(env, ctx, asm);
559             // FIX FOR 4071548
560             // 'StringBuffer.append' converts its argument as if by
561             // 'valueOf', treating character arrays specially.  This
562             // violates JLS 15.17.1.1, which requires that concatenation
563             // convert non-primitive arguments using 'toString'.  We force
564             // the treatment of all reference types as type 'Object', thus
565             // invoking an overloading of 'append' that has the required
566             // semantics.
567             Type argType[] =
568                 { (type.inMask(TM_REFERENCE) && type != Type.tString)
569                   ? Type.tObject
570                   : type };
571             f = sbClsDef.matchMethod(env, sourceClass, idAppend, argType);
572             asm.add(where, opc_invokevirtual, f);
573         }
574     }
575 
576     /**
577      * Code
578      */
579     void codeDup(Environment env, Context ctx, Assembler asm, int items, int depth) {
580         switch (items) {
581           case 0:
582             return;
583 
584           case 1:
585             switch (depth) {
586               case 0:
587                 asm.add(where, opc_dup);
588                 return;
589               case 1:
590                 asm.add(where, opc_dup_x1);
591                 return;
592               case 2:
593                 asm.add(where, opc_dup_x2);
594                 return;
595 
596             }
597             break;
598           case 2:
599             switch (depth) {
600               case 0:
601                 asm.add(where, opc_dup2);
602                 return;
603               case 1:
604                 asm.add(where, opc_dup2_x1);
605                 return;
606               case 2:
607                 asm.add(where, opc_dup2_x2);
608                 return;
609 
610             }
611             break;
612         }
613         throw new CompilerError("can't dup: " + items + ", " + depth);
614     }
615 
616     void codeConversion(Environment env, Context ctx, Assembler asm, Type f, Type t) {
617         int from = f.getTypeCode();
618         int to = t.getTypeCode();
619 
620         switch (to) {
621           case TC_BOOLEAN:
622             if (from != TC_BOOLEAN) {
623                 break;
624             }
625             return;
626           case TC_BYTE:
627             if (from != TC_BYTE) {
628                 codeConversion(env, ctx, asm, f, Type.tInt);
629                 asm.add(where, opc_i2b);
630             }
631             return;
632           case TC_CHAR:
633             if (from != TC_CHAR) {
634                 codeConversion(env, ctx, asm, f, Type.tInt);
635                 asm.add(where, opc_i2c);
636             }
637             return;
638           case TC_SHORT:
639             if (from != TC_SHORT) {
640                 codeConversion(env, ctx, asm, f, Type.tInt);
641                 asm.add(where, opc_i2s);
642             }
643             return;
644           case TC_INT:
645             switch (from) {
646               case TC_BYTE:
647               case TC_CHAR:
648               case TC_SHORT:
649               case TC_INT:
650                 return;
651               case TC_LONG:
652                 asm.add(where, opc_l2i);
653                 return;
654               case TC_FLOAT:
655                 asm.add(where, opc_f2i);
656                 return;
657               case TC_DOUBLE:
658                 asm.add(where, opc_d2i);
659                 return;
660             }
661             break;
662           case TC_LONG:
663             switch (from) {
664               case TC_BYTE:
665               case TC_CHAR:
666               case TC_SHORT:
667               case TC_INT:
668                 asm.add(where, opc_i2l);
669                 return;
670               case TC_LONG:
671                 return;
672               case TC_FLOAT:
673                 asm.add(where, opc_f2l);
674                 return;
675               case TC_DOUBLE:
676                 asm.add(where, opc_d2l);
677                 return;
678             }
679             break;
680           case TC_FLOAT:
681             switch (from) {
682               case TC_BYTE:
683               case TC_CHAR:
684               case TC_SHORT:
685               case TC_INT:
686                 asm.add(where, opc_i2f);
687                 return;
688               case TC_LONG:
689                 asm.add(where, opc_l2f);
690                 return;
691               case TC_FLOAT:
692                 return;
693               case TC_DOUBLE:
694                 asm.add(where, opc_d2f);
695                 return;
696             }
697             break;
698           case TC_DOUBLE:
699             switch (from) {
700               case TC_BYTE:
701               case TC_CHAR:
702               case TC_SHORT:
703               case TC_INT:
704                 asm.add(where, opc_i2d);
705                 return;
706               case TC_LONG:
707                 asm.add(where, opc_l2d);
708                 return;
709               case TC_FLOAT:
710                 asm.add(where, opc_f2d);
711                 return;
712               case TC_DOUBLE:
713                 return;
714             }
715             break;
716 
717           case TC_CLASS:
718             switch (from) {
719               case TC_NULL:
720                 return;
721               case TC_CLASS:
722               case TC_ARRAY:
723                 try {
724                     if (!env.implicitCast(f, t)) {
725                         asm.add(where, opc_checkcast, env.getClassDeclaration(t));
726                     }
727                 } catch (ClassNotFound e) {
728                     throw new CompilerError(e);
729                 }
730                 return;
731             }
732 
733             break;
734 
735           case TC_ARRAY:
736             switch (from) {
737               case TC_NULL:
738                 return;
739               case TC_CLASS:
740               case TC_ARRAY:
741                 try {
742                     if (!env.implicitCast(f, t)) {
743                         asm.add(where, opc_checkcast, t);
744                     }
745                     return;
746                 } catch (ClassNotFound e) {
747                     throw new CompilerError(e);
748                 }
749             }
750             break;
751         }
752         throw new CompilerError("codeConversion: " + from + ", " + to);
753     }
754 
755     /**
756      * Check if the first thing is a constructor invocation
757      */
758     public Expression firstConstructor() {
759         return null;
760     }
761 
762     /**
763      * Create a copy of the expression for method inlining
764      */
765     public Expression copyInline(Context ctx) {
766         return (Expression)clone();
767     }
768 
769     /**
770      * Print
771      */
772     public void print(PrintStream out) {
773         out.print(opNames[op]);
774     }
775 }