ClassConstantPool.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.commons.compress.harmony.unpack200.bytecode;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.TreeSet;
- import org.apache.commons.compress.harmony.unpack200.Segment;
- /**
- * The Class constant pool
- */
- public class ClassConstantPool {
- protected HashSet<ClassFileEntry> entriesContainsSet = new HashSet<>();
- protected HashSet<ClassFileEntry> othersContainsSet = new HashSet<>();
- private final HashSet<ClassFileEntry> mustStartClassPool = new HashSet<>();
- protected Map<ClassFileEntry, Integer> indexCache;
- private final List<ClassFileEntry> others = new ArrayList<>(500);
- private final List<ClassFileEntry> entries = new ArrayList<>(500);
- private boolean resolved;
- public ClassFileEntry add(final ClassFileEntry entry) {
- if (entry instanceof ByteCode) {
- return null;
- }
- if (entry instanceof ConstantPoolEntry) {
- if (entriesContainsSet.add(entry)) {
- entries.add(entry);
- }
- } else if (othersContainsSet.add(entry)) {
- others.add(entry);
- }
- return entry;
- }
- public void addNestedEntries() {
- boolean added = true;
- // initial assignment
- final List<ClassFileEntry> parents = new ArrayList<>(512);
- final List<ClassFileEntry> children = new ArrayList<>(512);
- // adding old entries
- parents.addAll(entries);
- parents.addAll(others);
- // while there any parents to traverse and at least one change in target
- // storage was made
- while (added || parents.size() > 0) {
- children.clear();
- final int entriesOriginalSize = entries.size();
- final int othersOriginalSize = others.size();
- // get the parents' children and add them to buffer
- // concurrently add parents to target storage
- for (int indexParents = 0; indexParents < parents.size(); indexParents++) {
- final ClassFileEntry entry = parents.get(indexParents);
- // traverse children
- final ClassFileEntry[] entryChildren = entry.getNestedClassFileEntries();
- children.addAll(Arrays.asList(entryChildren));
- final boolean isAtStart = entry instanceof ByteCode && ((ByteCode) entry).nestedMustStartClassPool();
- if (isAtStart) {
- mustStartClassPool.addAll(Arrays.asList(entryChildren));
- }
- // add parent
- add(entry);
- }
- added = !(entries.size() == entriesOriginalSize && others.size() == othersOriginalSize);
- // parents are not needed anymore
- // children now become parents
- parents.clear();
- parents.addAll(children);
- }
- }
- public ClassFileEntry addWithNestedEntries(final ClassFileEntry entry) {
- add(entry);
- for (final ClassFileEntry nestedEntry : entry.getNestedClassFileEntries()) {
- addWithNestedEntries(nestedEntry);
- }
- return entry;
- }
- public List<ClassFileEntry> entries() {
- return Collections.unmodifiableList(entries);
- }
- public ClassFileEntry get(int i) {
- if (!resolved) {
- throw new IllegalStateException("Constant pool is not yet resolved; this does not make any sense");
- }
- return entries.get(--i);
- }
- public int indexOf(final ClassFileEntry entry) {
- if (!resolved) {
- throw new IllegalStateException("Constant pool is not yet resolved; this does not make any sense");
- }
- if (null == indexCache) {
- throw new IllegalStateException("Index cache is not initialized!");
- }
- final Integer entryIndex = indexCache.get(entry);
- // If the entry isn't found, answer -1, otherwise answer the entry.
- if (entryIndex != null) {
- return entryIndex.intValue() + 1;
- }
- return -1;
- }
- private void initialSort() {
- final TreeSet<ClassFileEntry> inCpAll = new TreeSet<>(Comparator.comparingInt(arg0 -> ((ConstantPoolEntry) arg0).getGlobalIndex()));
- final TreeSet<ClassFileEntry> cpUtf8sNotInCpAll = new TreeSet<>(Comparator.comparing(arg0 -> ((CPUTF8) arg0).underlyingString()));
- final TreeSet<ClassFileEntry> cpClassesNotInCpAll = new TreeSet<>(Comparator.comparing(arg0 -> ((CPClass) arg0).getName()));
- for (final ClassFileEntry entry2 : entries) {
- final ConstantPoolEntry entry = (ConstantPoolEntry) entry2;
- if (entry.getGlobalIndex() == -1) {
- if (entry instanceof CPUTF8) {
- cpUtf8sNotInCpAll.add(entry);
- } else if (entry instanceof CPClass) {
- cpClassesNotInCpAll.add(entry);
- } else {
- throw new Error("error");
- }
- } else {
- inCpAll.add(entry);
- }
- }
- entries.clear();
- entries.addAll(inCpAll);
- entries.addAll(cpUtf8sNotInCpAll);
- entries.addAll(cpClassesNotInCpAll);
- }
- public void resolve(final Segment segment) {
- initialSort();
- sortClassPool();
- resolved = true;
- entries.forEach(entry -> entry.resolve(this));
- others.forEach(entry -> entry.resolve(this));
- }
- public int size() {
- return entries.size();
- }
- protected void sortClassPool() {
- // Now that everything has been resolved, do one
- // final sort of the class pool. This fixes up
- // references to objects which need to be at the
- // start of the class pool
- final List<ClassFileEntry> startOfPool = new ArrayList<>(entries.size());
- final List<ClassFileEntry> finalSort = new ArrayList<>(entries.size());
- for (final ClassFileEntry entry : entries) {
- if (mustStartClassPool.contains(entry)) {
- startOfPool.add(entry);
- } else {
- finalSort.add(entry);
- }
- }
- // copy over and rebuild the cache
- //
- indexCache = new HashMap<>(entries.size());
- int index = 0;
- entries.clear();
- for (final ClassFileEntry entry : startOfPool) {
- indexCache.put(entry, Integer.valueOf(index));
- if (entry instanceof CPLong || entry instanceof CPDouble) {
- entries.add(entry); // these get 2 slots because of their size
- entries.add(entry);
- index += 2;
- } else {
- entries.add(entry);
- index += 1;
- }
- }
- for (final ClassFileEntry entry : finalSort) {
- indexCache.put(entry, Integer.valueOf(index));
- if (entry instanceof CPLong || entry instanceof CPDouble) {
- entries.add(entry); // these get 2 slots because of their size
- entries.add(entry);
- index += 2;
- } else {
- entries.add(entry);
- index += 1;
- }
- }
- }
- }