View Javadoc
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.io.PrintStream;
31  import java.util.Hashtable;
32  
33  /**
34   * WARNING: The contents of this source file are not part of any
35   * supported API.  Code that depends on them does so at its own risk:
36   * they are subject to change or removal without notice.
37   */
38  public
39  class ArrayAccessExpression extends UnaryExpression {
40  
41      /**
42       * The index expression for the array access.  Note that
43       * ArrayAccessExpression also `moonlights' as a structure for
44       * storing array types (like Object[]) which are used as part
45       * of cast expressions.  For properly formed array types, the
46       * value of index is null.  We need to be on the lookout for
47       * null indices in true array accesses, and non-null indices
48       * in array types.  We also need to make sure general purpose
49       * methods (like copyInline(), which is called for both) are
50       * prepared to handle either null or non-null indices.
51       */
52      Expression index;
53  
54      /**
55       * constructor
56       */
57      public ArrayAccessExpression(long where, Expression right, Expression index) {
58          super(ARRAYACCESS, where, Type.tError, right);
59          this.index = index;
60      }
61  
62      /**
63       * Check expression type
64       */
65      public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) {
66          vset = right.checkValue(env, ctx, vset, exp);
67          if (index == null) {
68              env.error(where, "array.index.required");
69              return vset;
70          }
71          vset = index.checkValue(env, ctx, vset, exp);
72          index = convert(env, ctx, Type.tInt, index);
73  
74          if (!right.type.isType(TC_ARRAY)) {
75              if (!right.type.isType(TC_ERROR)) {
76                  env.error(where, "not.array", right.type);
77              }
78              return vset;
79          }
80  
81          type = right.type.getElementType();
82          return vset;
83      }
84  
85      public Vset checkAmbigName(Environment env, Context ctx,
86                                 Vset vset, Hashtable exp,
87                                 UnaryExpression loc) {
88          if (index == null) {
89              vset = right.checkAmbigName(env, ctx, vset, exp, this);
90              if (right.type == Type.tPackage) {
91                  FieldExpression.reportFailedPackagePrefix(env, right);
92                  return vset;
93              }
94  
95              // Nope.  Is this field expression a type?
96              if (right instanceof TypeExpression) {
97                  Type atype = Type.tArray(right.type);
98                  loc.right = new TypeExpression(where, atype);
99                  return vset;
100             }
101 
102             env.error(where, "array.index.required");
103             return vset;
104         }
105         return super.checkAmbigName(env, ctx, vset, exp, loc);
106     }
107 
108     /*
109      * Check the array if it appears on the LHS of an assignment
110      */
111     public Vset checkLHS(Environment env, Context ctx,
112                          Vset vset, Hashtable exp) {
113         return checkValue(env, ctx, vset, exp);
114     }
115 
116     /*
117      * Check the array if it appears on the LHS of an op= expression
118      */
119     public Vset checkAssignOp(Environment env, Context ctx,
120                               Vset vset, Hashtable exp, Expression outside) {
121         return checkValue(env, ctx, vset, exp);
122     }
123 
124     /**
125      * An array access expression never requires the use of an access method to perform
126      * an assignment to an array element, though an access method may be required to
127      * fetch the array object itself.
128      */
129     public FieldUpdater getAssigner(Environment env, Context ctx) {
130         return null;
131     }
132 
133     /**
134      * An array access expression never requires a field updater.
135      */
136     public FieldUpdater getUpdater(Environment env, Context ctx) {
137         return null;
138     }
139 
140     /**
141      * Convert to a type
142      */
143     Type toType(Environment env, Context ctx) {
144         return toType(env, right.toType(env, ctx));
145     }
146     Type toType(Environment env, Type t) {
147         if (index != null) {
148             env.error(index.where, "array.dim.in.type");
149         }
150         return Type.tArray(t);
151     }
152 
153     /**
154      * Inline
155      */
156     public Expression inline(Environment env, Context ctx) {
157         // It isn't possible to simply replace an array access
158         // with a CommaExpression as happens with many binary
159         // operators, because array accesses may have side effects
160         // such as NullPointerException or IndexOutOfBoundsException.
161         right = right.inlineValue(env, ctx);
162         index = index.inlineValue(env, ctx);
163         return this;
164     }
165     public Expression inlineValue(Environment env, Context ctx) {
166         // inlineValue() should not end up being called when the index is
167         // null.  If it is null, we let this method fail with a
168         // NullPointerException.
169 
170         right = right.inlineValue(env, ctx);
171         index = index.inlineValue(env, ctx);
172         return this;
173     }
174     public Expression inlineLHS(Environment env, Context ctx) {
175         return inlineValue(env, ctx);
176     }
177 
178     /**
179      * Create a copy of the expression for method inlining
180      */
181     public Expression copyInline(Context ctx) {
182         ArrayAccessExpression e = (ArrayAccessExpression)clone();
183         e.right = right.copyInline(ctx);
184         if (index == null) {
185             // The index can be null when this node is being used to
186             // represent a type (e.g. Object[]) used in a cast expression.
187             // We need to copy such structures without complaint.
188             e.index = null;
189         } else {
190             e.index = index.copyInline(ctx);
191         }
192         return e;
193     }
194 
195     /**
196      * The cost of inlining this expression
197      */
198     public int costInline(int thresh, Environment env, Context ctx) {
199         // costInline() should not end up being called when the index is
200         // null.  If it is null, we let this method fail with a
201         // NullPointerException.
202 
203         return 1 + right.costInline(thresh, env, ctx)
204             + index.costInline(thresh, env, ctx);
205     }
206 
207     /**
208      * Code
209      */
210     int codeLValue(Environment env, Context ctx, Assembler asm) {
211         // codeLValue() should not end up being called when the index is
212         // null.  If it is null, we let this method fail with a
213         // NullPointerException.
214 
215         right.codeValue(env, ctx, asm);
216         index.codeValue(env, ctx, asm);
217         return 2;
218     }
219     void codeLoad(Environment env, Context ctx, Assembler asm) {
220         switch (type.getTypeCode()) {
221           case TC_BOOLEAN:
222           case TC_BYTE:
223             asm.add(where, opc_baload);
224             break;
225           case TC_CHAR:
226             asm.add(where, opc_caload);
227             break;
228           case TC_SHORT:
229             asm.add(where, opc_saload);
230             break;
231           default:
232             asm.add(where, opc_iaload + type.getTypeCodeOffset());
233         }
234     }
235     void codeStore(Environment env, Context ctx, Assembler asm) {
236         switch (type.getTypeCode()) {
237           case TC_BOOLEAN:
238           case TC_BYTE:
239             asm.add(where, opc_bastore);
240             break;
241           case TC_CHAR:
242             asm.add(where, opc_castore);
243             break;
244           case TC_SHORT:
245             asm.add(where, opc_sastore);
246             break;
247           default:
248             asm.add(where, opc_iastore + type.getTypeCodeOffset());
249         }
250     }
251     public void codeValue(Environment env, Context ctx, Assembler asm) {
252         codeLValue(env, ctx, asm);
253         codeLoad(env, ctx, asm);
254     }
255 
256 
257     /**
258      * Print
259      */
260     public void print(PrintStream out) {
261         out.print("(" + opNames[op] + " ");
262         right.print(out);
263         out.print(" ");
264         if (index != null) {
265             index.print(out);
266         } else {
267         out.print("<empty>");
268         }
269         out.print(")");
270     }
271 }