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
26package sun.tools.tree;
27
28import sun.tools.java.*;
29import sun.tools.asm.Assembler;
30import java.io.PrintStream;
31import 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 */
38public
39class 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<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
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     */
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     */
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     */
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}
272