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
26package sun.tools.tree;
27
28import sun.tools.java.*;
29import sun.tools.asm.Label;
30import sun.tools.asm.Assembler;
31import java.io.PrintStream;
32import 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 */
39public
40class 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<Object, Object> exp) {
196        return vset;
197    }
198    public Vset checkInitializer(Environment env, Context ctx, Vset vset, Type t, Hashtable<Object, Object> exp) {
199        return checkValue(env, ctx, vset, exp);
200    }
201    public Vset check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp) {
202        throw new CompilerError("check failed");
203    }
204
205    public Vset checkLHS(Environment env, Context ctx,
206                            Vset vset, Hashtable<Object, Object> exp) {
207        env.error(where, "invalid.lhs.assignment");
208        type = Type.tError;
209        return vset;
210    }
211
212    /**
213     * Return a {@code FieldUpdater} object to be used in updating the
214     * value of the location denoted by {@code this}, 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} object to be used in updating the value of the
232     * location denoted by {@code this}, 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<Object, Object> 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 {@code TypeExpression}.
264     * If a node decides it can only be a package prefix, it sets its
265     * type to {@code Type.tPackage}.  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<Object, Object> 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<Object, Object> 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<Object, Object> 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, 0);
436            asm.add(true, where, opc_goto, l2);
437            asm.add(l1);
438            asm.add(true, where, opc_ldc, 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}
776