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<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 }