• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.rop.cst;
18 
19 import com.android.dx.util.ExceptionWithContext;
20 import com.android.dx.util.Hex;
21 import com.android.dx.util.MutabilityControl;
22 
23 /**
24  * Standard implementation of {@link ConstantPool}, which directly stores
25  * an array of {@link Constant} objects and can be made immutable.
26  */
27 public final class StdConstantPool
28         extends MutabilityControl implements ConstantPool {
29     /** {@code non-null;} array of entries */
30     private final Constant[] entries;
31 
32     /**
33      * Constructs an instance. All indices initially contain {@code null}.
34      *
35      * @param size the size of the pool; this corresponds to the
36      * class file field {@code constant_pool_count}, and is in fact
37      * always at least one more than the actual size of the constant pool,
38      * as element {@code 0} is always invalid.
39      */
StdConstantPool(int size)40     public StdConstantPool(int size) {
41         super(size > 1);
42 
43         if (size < 1) {
44             throw new IllegalArgumentException("size < 1");
45         }
46 
47         entries = new Constant[size];
48     }
49 
50     /** {@inheritDoc} */
size()51     public int size() {
52         return entries.length;
53     }
54 
55     /** {@inheritDoc} */
getOrNull(int n)56     public Constant getOrNull(int n) {
57         try {
58             return entries[n];
59         } catch (IndexOutOfBoundsException ex) {
60             // Translate the exception.
61             return throwInvalid(n);
62         }
63     }
64 
65     /** {@inheritDoc} */
get0Ok(int n)66     public Constant get0Ok(int n) {
67         if (n == 0) {
68             return null;
69         }
70 
71         return get(n);
72     }
73 
74     /** {@inheritDoc} */
get(int n)75     public Constant get(int n) {
76         try {
77             Constant result = entries[n];
78 
79             if (result == null) {
80                 throwInvalid(n);
81             }
82 
83             return result;
84         } catch (IndexOutOfBoundsException ex) {
85             // Translate the exception.
86             return throwInvalid(n);
87         }
88     }
89 
90     /**
91      * Sets the entry at the given index.
92      *
93      * @param n {@code >= 1, < size();} which entry
94      * @param cst {@code null-ok;} the constant to store
95      */
set(int n, Constant cst)96     public void set(int n, Constant cst) {
97         throwIfImmutable();
98 
99         boolean cat2 = (cst != null) && cst.isCategory2();
100 
101         if (n < 1) {
102             throw new IllegalArgumentException("n < 1");
103         }
104 
105         if (cat2) {
106             // Storing a category-2 entry nulls out the next index.
107             if (n == (entries.length - 1)) {
108                 throw new IllegalArgumentException("(n == size - 1) && " +
109                                                    "cst.isCategory2()");
110             }
111             entries[n + 1] = null;
112         }
113 
114         if ((cst != null) && (entries[n] == null)) {
115             /*
116              * Overwriting the second half of a category-2 entry nulls out
117              * the first half.
118              */
119             Constant prev = entries[n - 1];
120             if ((prev != null) && prev.isCategory2()) {
121                 entries[n - 1] = null;
122             }
123         }
124 
125         entries[n] = cst;
126     }
127 
128     /**
129      * Throws the right exception for an invalid cpi.
130      *
131      * @param idx the bad cpi
132      * @return never
133      * @throws ExceptionWithContext always thrown
134      */
throwInvalid(int idx)135     private static Constant throwInvalid(int idx) {
136         throw new ExceptionWithContext("invalid constant pool index " +
137                                        Hex.u2(idx));
138     }
139 }
140