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      */
ArrayAccessExpression(long where, Expression right, Expression index)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      */
checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)65     public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> 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 
checkAmbigName(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp, UnaryExpression loc)85     public Vset checkAmbigName(Environment env, Context ctx,
86                                Vset vset, Hashtable<Object, Object> 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      */
checkLHS(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)111     public Vset checkLHS(Environment env, Context ctx,
112                          Vset vset, Hashtable<Object, Object> 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      */
checkAssignOp(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp, Expression outside)119     public Vset checkAssignOp(Environment env, Context ctx,
120                               Vset vset, Hashtable<Object, Object> 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      */
getAssigner(Environment env, Context ctx)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      */
getUpdater(Environment env, Context ctx)136     public FieldUpdater getUpdater(Environment env, Context ctx) {
137         return null;
138     }
139 
140     /**
141      * Convert to a type
142      */
toType(Environment env, Context ctx)143     Type toType(Environment env, Context ctx) {
144         return toType(env, right.toType(env, ctx));
145     }
toType(Environment env, Type t)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      */
inline(Environment env, Context ctx)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     }
inlineValue(Environment env, Context ctx)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     }
inlineLHS(Environment env, Context ctx)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      */
copyInline(Context ctx)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      */
costInline(int thresh, Environment env, Context ctx)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      */
codeLValue(Environment env, Context ctx, Assembler asm)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     }
codeLoad(Environment env, Context ctx, Assembler asm)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     }
codeStore(Environment env, Context ctx, Assembler asm)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     }
codeValue(Environment env, Context ctx, Assembler asm)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      */
print(PrintStream out)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 }
272