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