Home | History | Annotate | Download | only in cst
      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      */
     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} */
     51     public int size() {
     52         return entries.length;
     53     }
     54 
     55     /** {@inheritDoc} */
     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} */
     66     public Constant get0Ok(int n) {
     67         if (n == 0) {
     68             return null;
     69         }
     70 
     71         return get(n);
     72     }
     73 
     74     /** {@inheritDoc} */
     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      */
     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      */
    135     private static Constant throwInvalid(int idx) {
    136         throw new ExceptionWithContext("invalid constant pool index " +
    137                                        Hex.u2(idx));
    138     }
    139 }
    140