| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.dx.rop.cst; |
| |
| import com.android.dx.util.ExceptionWithContext; |
| import com.android.dx.util.Hex; |
| import com.android.dx.util.MutabilityControl; |
| |
| /** |
| * Standard implementation of {@link ConstantPool}, which directly stores |
| * an array of {@link Constant} objects and can be made immutable. |
| */ |
| public final class StdConstantPool |
| extends MutabilityControl implements ConstantPool { |
| /** {@code non-null;} array of entries */ |
| private final Constant[] entries; |
| |
| /** |
| * Constructs an instance. All indices initially contain {@code null}. |
| * |
| * @param size the size of the pool; this corresponds to the |
| * class file field {@code constant_pool_count}, and is in fact |
| * always at least one more than the actual size of the constant pool, |
| * as element {@code 0} is always invalid. |
| */ |
| public StdConstantPool(int size) { |
| super(size > 1); |
| |
| if (size < 1) { |
| throw new IllegalArgumentException("size < 1"); |
| } |
| |
| entries = new Constant[size]; |
| } |
| |
| /** {@inheritDoc} */ |
| public int size() { |
| return entries.length; |
| } |
| |
| /** {@inheritDoc} */ |
| public Constant getOrNull(int n) { |
| try { |
| return entries[n]; |
| } catch (IndexOutOfBoundsException ex) { |
| // Translate the exception. |
| return throwInvalid(n); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public Constant get0Ok(int n) { |
| if (n == 0) { |
| return null; |
| } |
| |
| return get(n); |
| } |
| |
| /** {@inheritDoc} */ |
| public Constant get(int n) { |
| try { |
| Constant result = entries[n]; |
| |
| if (result == null) { |
| throwInvalid(n); |
| } |
| |
| return result; |
| } catch (IndexOutOfBoundsException ex) { |
| // Translate the exception. |
| return throwInvalid(n); |
| } |
| } |
| |
| /** |
| * Sets the entry at the given index. |
| * |
| * @param n {@code >= 1, < size();} which entry |
| * @param cst {@code null-ok;} the constant to store |
| */ |
| public void set(int n, Constant cst) { |
| throwIfImmutable(); |
| |
| boolean cat2 = (cst != null) && cst.isCategory2(); |
| |
| if (n < 1) { |
| throw new IllegalArgumentException("n < 1"); |
| } |
| |
| if (cat2) { |
| // Storing a category-2 entry nulls out the next index. |
| if (n == (entries.length - 1)) { |
| throw new IllegalArgumentException("(n == size - 1) && " + |
| "cst.isCategory2()"); |
| } |
| entries[n + 1] = null; |
| } |
| |
| if ((cst != null) && (entries[n] == null)) { |
| /* |
| * Overwriting the second half of a category-2 entry nulls out |
| * the first half. |
| */ |
| Constant prev = entries[n - 1]; |
| if ((prev != null) && prev.isCategory2()) { |
| entries[n - 1] = null; |
| } |
| } |
| |
| entries[n] = cst; |
| } |
| |
| /** |
| * Throws the right exception for an invalid cpi. |
| * |
| * @param idx the bad cpi |
| * @return never |
| * @throws ExceptionWithContext always thrown |
| */ |
| private static Constant throwInvalid(int idx) { |
| throw new ExceptionWithContext("invalid constant pool index " + |
| Hex.u2(idx)); |
| } |
| } |