183c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek/*
2eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek * Copyright (C) 2007 The Android Open Source Project
3eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek *
4eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek * Licensed under the Apache License, Version 2.0 (the "License");
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner * you may not use this file except in compliance with the License.
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner * You may obtain a copy of the License at
7eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek *
8eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek *      http://www.apache.org/licenses/LICENSE-2.0
9eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek *
1083c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek * Unless required by applicable law or agreed to in writing, software
1183c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek * distributed under the License is distributed on an "AS IS" BASIS,
12eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek * See the License for the specific language governing permissions and
14eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek * limitations under the License.
1583c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek */
1683c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek
17eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenekpackage com.android.dx.rop.cst;
18e41611aa2237d06a0ef61db4528fb2883a8defcdTed Kremenek
19eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenekimport com.android.dx.util.ExceptionWithContext;
204c3fbe33194cd9b1bfff773647ed785b403e1ba5Ted Kremenekimport com.android.dx.util.Hex;
215226755ab5ce6346f98b5f41cdcffbe84c5bb484Ted Kremenekimport com.android.dx.util.MutabilityControl;
226bad354120ce0d35901e86ca63e5534b7b9ed092Ted Kremenek
234c3fbe33194cd9b1bfff773647ed785b403e1ba5Ted Kremenek/**
2459753441b6391a9843eff287f0adb2614153b7c8Ted Kremenek * Standard implementation of {@link ConstantPool}, which directly stores
25eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek * an array of {@link Constant} objects and can be made immutable.
26eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek */
2705e14cd46ef44c07385aae96ec2fdcb9bf7e9467Ted Kremenekpublic final class StdConstantPool
2883c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek        extends MutabilityControl implements ConstantPool {
29eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek    /** {@code non-null;} array of entries */
30cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek    private final Constant[] entries;
31cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek
32cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek    /**
33cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     * Constructs an instance. All indices initially contain {@code null}.
34cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     *
35cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     * @param size the size of the pool; this corresponds to the
36cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     * class file field {@code constant_pool_count}, and is in fact
37cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     * always at least one more than the actual size of the constant pool,
38cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     * as element {@code 0} is always invalid.
39cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     */
40cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek    public StdConstantPool(int size) {
41cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek        super(size > 1);
42cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek
43cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek        if (size < 1) {
44cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek            throw new IllegalArgumentException("size < 1");
45f4be8ee748831bc23e35b542e6c1bb6d1eb49baaTed Kremenek        }
467090d5465de7ca620da16211cf886edf1edc1f1fTed Kremenek
474c3fbe33194cd9b1bfff773647ed785b403e1ba5Ted Kremenek        entries = new Constant[size];
48d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek    }
49d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek
50d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek    /** {@inheritDoc} */
51e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek    public int size() {
52d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek        return entries.length;
53d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek    }
54e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek
55d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek    /** {@inheritDoc} */
56d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek    public Constant getOrNull(int n) {
57d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek        try {
58d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek            return entries[n];
59f4be8ee748831bc23e35b542e6c1bb6d1eb49baaTed Kremenek        } catch (IndexOutOfBoundsException ex) {
60d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek            // Translate the exception.
61d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek            return throwInvalid(n);
62d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek        }
63e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek    }
64f4be8ee748831bc23e35b542e6c1bb6d1eb49baaTed Kremenek
6583c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek    /** {@inheritDoc} */
66d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek    public Constant get0Ok(int n) {
67d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek        if (n == 0) {
68e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek            return null;
69d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek        }
70e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek
71d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek        return get(n);
72e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek    }
73d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek
74eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek    /** {@inheritDoc} */
7583c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek    public Constant get(int n) {
76d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek        try {
77d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek            Constant result = entries[n];
78d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek
79d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek            if (result == null) {
80d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek                throwInvalid(n);
81d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek            }
82d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek
83d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek            return result;
84d452758bb6b59340528a26def9ecc24b329d4ecfTed Kremenek        } catch (IndexOutOfBoundsException ex) {
855226755ab5ce6346f98b5f41cdcffbe84c5bb484Ted Kremenek            // Translate the exception.
86d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek            return throwInvalid(n);
87d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek        }
88d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek    }
89e8063ae53bd241de10ba1053054d06867a5c56abTed Kremenek
902680b5f926fad29c1a2b2723a70d189f4b637979Ted Kremenek    /**
91eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek     * Sets the entry at the given index.
9283c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek     *
9383c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek     * @param n {@code >= 1, < size();} which entry
94eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek     * @param cst {@code null-ok;} the constant to store
95ab422d17dce198f2af9851340ea7384771a2a8c5Ted Kremenek     */
96ab422d17dce198f2af9851340ea7384771a2a8c5Ted Kremenek    public void set(int n, Constant cst) {
9783c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek        throwIfImmutable();
9883c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek
99d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek        boolean cat2 = (cst != null) && cst.isCategory2();
100bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek
101eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek        if (n < 1) {
10283c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek            throw new IllegalArgumentException("n < 1");
103d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek        }
10483c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek
10583c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek        if (cat2) {
106eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek            // Storing a category-2 entry nulls out the next index.
10783c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek            if (n == (entries.length - 1)) {
10883c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek                throw new IllegalArgumentException("(n == size - 1) && " +
109bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek                                                   "cst.isCategory2()");
110eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek            }
11183c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek            entries[n + 1] = null;
11283c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek        }
113eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek
11483c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek        if ((cst != null) && (entries[n] == null)) {
115bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek            /*
11683c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek             * Overwriting the second half of a category-2 entry nulls out
117d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek             * the first half.
118bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek             */
11983c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek            Constant prev = entries[n - 1];
12083c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek            if ((prev != null) && prev.isCategory2()) {
121d6b9e37311013bdf24fd709f7e9962e3b141e6fbTed Kremenek                entries[n - 1] = null;
12283c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek            }
123bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek        }
124bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek
12583c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek        entries[n] = cst;
12683c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek    }
127bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek
12883c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek    /**
12983c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek     * Throws the right exception for an invalid cpi.
13083c01da96f57cf732a5da9a83e2981241f205dc4Ted Kremenek     *
131bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek     * @param idx the bad cpi
132bd129696c554fbbcd9405104641e292f0fb4678dTed Kremenek     * @return never
133eb19188e668d0ad2c968fc0286a6922f9194deb4Ted Kremenek     * @throws ExceptionWithContext always thrown
134cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek     */
135cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek    private static Constant throwInvalid(int idx) {
136cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek        throw new ExceptionWithContext("invalid constant pool index " +
137cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek                                       Hex.u2(idx));
138cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek    }
139cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek}
140cdd4f1783da7c7565be2376d14ca6ab2625aa4b6Ted Kremenek