1 /*
   2  * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.tools.tree;
  27 
  28 import sun.tools.java.*;
  29 import sun.tools.asm.Assembler;
  30 import java.util.Hashtable;
  31 
  32 /**
  33  * WARNING: The contents of this source file are not part of any
  34  * supported API.  Code that depends on them does so at its own risk:
  35  * they are subject to change or removal without notice.
  36  */
  37 public
  38 class IncDecExpression extends UnaryExpression {
  39 
  40     private FieldUpdater updater = null;
  41 
  42     /**
  43      * Constructor
  44      */
  45     public IncDecExpression(int op, long where, Expression right) {
  46         super(op, where, right.type, right);
  47     }
  48 
  49     /**
  50      * Check an increment or decrement expression
  51      */
  52     public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) {
  53         vset = right.checkAssignOp(env, ctx, vset, exp, this);
  54         if (right.type.inMask(TM_NUMBER)) {
  55             type = right.type;
  56         } else {
  57             if (!right.type.isType(TC_ERROR)) {
  58                 env.error(where, "invalid.arg.type", right.type, opNames[op]);
  59             }
  60             type = Type.tError;
  61         }
  62         updater = right.getUpdater(env, ctx);  // Must be called after 'checkAssignOp'.
  63         return vset;
  64     }
  65 
  66     /**
  67      * Check void expression
  68      */
  69     public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
  70         return checkValue(env, ctx, vset, exp);
  71     }
  72 
  73     /**
  74      * Inline
  75      */
  76     public Expression inline(Environment env, Context ctx) {
  77         return inlineValue(env, ctx);
  78     }
  79     public Expression inlineValue(Environment env, Context ctx) {
  80         // Why not inlineLHS?  But that does not work.
  81         right = right.inlineValue(env, ctx);
  82         if (updater != null) {
  83             updater = updater.inline(env, ctx);
  84         }
  85         return this;
  86     }
  87 
  88     public int costInline(int thresh, Environment env, Context ctx) {
  89         if (updater == null) {
  90             if ((right.op == IDENT) && type.isType(TC_INT) &&
  91                 (((IdentifierExpression)right).field.isLocal())) {
  92                 // Increment variable in place.  Count 3 bytes for 'iinc'.
  93                 return 3;
  94             }
  95             // Cost to load lhs reference, fetch local, increment, and store.
  96             // Load/store cost will be higher if variable is a field.  Note that
  97             // costs are highly approximate. See 'AssignOpExpression.costInline'
  98             // Does not account for cost of conversions,or duplications in
  99             // value-needed context..
 100             return right.costInline(thresh, env, ctx) + 4;
 101         } else {
 102             // Cost of two access method calls (get/set) + cost of increment.
 103             return updater.costInline(thresh, env, ctx, true) + 1;
 104         }
 105     }
 106 
 107 
 108     /**
 109      * Code
 110      */
 111 
 112     private void codeIncDecOp(Assembler asm, boolean inc) {
 113         switch (type.getTypeCode()) {
 114           case TC_BYTE:
 115             asm.add(where, opc_ldc, new Integer(1));
 116             asm.add(where, inc ? opc_iadd : opc_isub);
 117             asm.add(where, opc_i2b);
 118             break;
 119           case TC_SHORT:
 120             asm.add(where, opc_ldc, new Integer(1));
 121             asm.add(where, inc ? opc_iadd : opc_isub);
 122             asm.add(where, opc_i2s);
 123             break;
 124           case TC_CHAR:
 125             asm.add(where, opc_ldc, new Integer(1));
 126             asm.add(where, inc ? opc_iadd : opc_isub);
 127             asm.add(where, opc_i2c);
 128             break;
 129           case TC_INT:
 130             asm.add(where, opc_ldc, new Integer(1));
 131             asm.add(where, inc ? opc_iadd : opc_isub);
 132             break;
 133           case TC_LONG:
 134             asm.add(where, opc_ldc2_w, 1L);
 135             asm.add(where, inc ? opc_ladd : opc_lsub);
 136             break;
 137           case TC_FLOAT:
 138             asm.add(where, opc_ldc, new Float(1));
 139             asm.add(where, inc ? opc_fadd : opc_fsub);
 140             break;
 141           case TC_DOUBLE:
 142             asm.add(where, opc_ldc2_w, new Double(1));
 143             asm.add(where, inc ? opc_dadd : opc_dsub);
 144             break;
 145           default:
 146             throw new CompilerError("invalid type");
 147         }
 148     }
 149 
 150     void codeIncDec(Environment env, Context ctx, Assembler asm, boolean inc, boolean prefix, boolean valNeeded) {
 151 
 152         // The 'iinc' instruction cannot be used if an access method call is required.
 153         if ((right.op == IDENT) && type.isType(TC_INT) &&
 154             (((IdentifierExpression)right).field.isLocal()) && updater == null) {
 155             if (valNeeded && !prefix) {
 156                 right.codeLoad(env, ctx, asm);
 157             }
 158             int v = ((LocalMember)((IdentifierExpression)right).field).number;
 159             int[] operands = { v, inc ? 1 : -1 };
 160             asm.add(where, opc_iinc, operands);
 161             if (valNeeded && prefix) {
 162                 right.codeLoad(env, ctx, asm);
 163             }
 164             return;
 165 
 166         }
 167 
 168         if (updater == null) {
 169             // Field is directly accessible.
 170             int depth = right.codeLValue(env, ctx, asm);
 171             codeDup(env, ctx, asm, depth, 0);
 172             right.codeLoad(env, ctx, asm);
 173             if (valNeeded && !prefix) {
 174                 codeDup(env, ctx, asm, type.stackSize(), depth);
 175             }
 176             codeIncDecOp(asm, inc);
 177             if (valNeeded && prefix) {
 178                 codeDup(env, ctx, asm, type.stackSize(), depth);
 179             }
 180             right.codeStore(env, ctx, asm);
 181         } else {
 182             // Must use access methods.
 183             updater.startUpdate(env, ctx, asm, (valNeeded && !prefix));
 184             codeIncDecOp(asm, inc);
 185             updater.finishUpdate(env, ctx, asm, (valNeeded && prefix));
 186         }
 187     }
 188 
 189 }