/* * 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.dexgen.rop.cst; import com.android.dexgen.util.ExceptionWithContext; import com.android.dexgen.util.Hex; import com.android.dexgen.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)); } }