1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.harmony.unpack200.bytecode;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.TreeSet;
30
31 import org.apache.commons.compress.harmony.unpack200.Segment;
32
33
34
35
36 public class ClassConstantPool {
37
38 protected HashSet<ClassFileEntry> entriesContainsSet = new HashSet<>();
39 protected HashSet<ClassFileEntry> othersContainsSet = new HashSet<>();
40
41 private final HashSet<ClassFileEntry> mustStartClassPool = new HashSet<>();
42
43 protected Map<ClassFileEntry, Integer> indexCache;
44
45 private final List<ClassFileEntry> others = new ArrayList<>(500);
46 private final List<ClassFileEntry> entries = new ArrayList<>(500);
47
48 private boolean resolved;
49
50 public ClassFileEntry add(final ClassFileEntry entry) {
51 if (entry instanceof ByteCode) {
52 return null;
53 }
54 if (entry instanceof ConstantPoolEntry) {
55 if (entriesContainsSet.add(entry)) {
56 entries.add(entry);
57 }
58 } else if (othersContainsSet.add(entry)) {
59 others.add(entry);
60 }
61
62 return entry;
63 }
64
65 public void addNestedEntries() {
66 boolean added = true;
67
68
69 final List<ClassFileEntry> parents = new ArrayList<>(512);
70 final List<ClassFileEntry> children = new ArrayList<>(512);
71
72
73 parents.addAll(entries);
74 parents.addAll(others);
75
76
77
78 while (added || parents.size() > 0) {
79
80 children.clear();
81
82 final int entriesOriginalSize = entries.size();
83 final int othersOriginalSize = others.size();
84
85
86
87 for (int indexParents = 0; indexParents < parents.size(); indexParents++) {
88 final ClassFileEntry entry = parents.get(indexParents);
89
90
91 final ClassFileEntry[] entryChildren = entry.getNestedClassFileEntries();
92 children.addAll(Arrays.asList(entryChildren));
93
94 final boolean isAtStart = entry instanceof ByteCode && ((ByteCode) entry).nestedMustStartClassPool();
95
96 if (isAtStart) {
97 mustStartClassPool.addAll(Arrays.asList(entryChildren));
98 }
99
100
101 add(entry);
102 }
103
104 added = !(entries.size() == entriesOriginalSize && others.size() == othersOriginalSize);
105
106
107
108 parents.clear();
109 parents.addAll(children);
110 }
111 }
112
113 public ClassFileEntry addWithNestedEntries(final ClassFileEntry entry) {
114 add(entry);
115 for (final ClassFileEntry nestedEntry : entry.getNestedClassFileEntries()) {
116 addWithNestedEntries(nestedEntry);
117 }
118 return entry;
119 }
120
121 public List<ClassFileEntry> entries() {
122 return Collections.unmodifiableList(entries);
123 }
124
125 public ClassFileEntry get(int i) {
126 if (!resolved) {
127 throw new IllegalStateException("Constant pool is not yet resolved; this does not make any sense");
128 }
129 return entries.get(--i);
130 }
131
132 public int indexOf(final ClassFileEntry entry) {
133 if (!resolved) {
134 throw new IllegalStateException("Constant pool is not yet resolved; this does not make any sense");
135 }
136 if (null == indexCache) {
137 throw new IllegalStateException("Index cache is not initialized!");
138 }
139 final Integer entryIndex = indexCache.get(entry);
140
141 if (entryIndex != null) {
142 return entryIndex.intValue() + 1;
143 }
144 return -1;
145 }
146
147 private void initialSort() {
148 final TreeSet<ClassFileEntry> inCpAll = new TreeSet<>(Comparator.comparingInt(arg0 -> ((ConstantPoolEntry) arg0).getGlobalIndex()));
149 final TreeSet<ClassFileEntry> cpUtf8sNotInCpAll = new TreeSet<>(Comparator.comparing(arg0 -> ((CPUTF8) arg0).underlyingString()));
150 final TreeSet<ClassFileEntry> cpClassesNotInCpAll = new TreeSet<>(Comparator.comparing(arg0 -> ((CPClass) arg0).getName()));
151
152 for (final ClassFileEntry entry2 : entries) {
153 final ConstantPoolEntry entry = (ConstantPoolEntry) entry2;
154 if (entry.getGlobalIndex() == -1) {
155 if (entry instanceof CPUTF8) {
156 cpUtf8sNotInCpAll.add(entry);
157 } else if (entry instanceof CPClass) {
158 cpClassesNotInCpAll.add(entry);
159 } else {
160 throw new Error("error");
161 }
162 } else {
163 inCpAll.add(entry);
164 }
165 }
166 entries.clear();
167 entries.addAll(inCpAll);
168 entries.addAll(cpUtf8sNotInCpAll);
169 entries.addAll(cpClassesNotInCpAll);
170 }
171
172 public void resolve(final Segment segment) {
173 initialSort();
174 sortClassPool();
175
176 resolved = true;
177
178 entries.forEach(entry -> entry.resolve(this));
179 others.forEach(entry -> entry.resolve(this));
180 }
181
182 public int size() {
183 return entries.size();
184 }
185
186 protected void sortClassPool() {
187
188
189
190
191
192 final List<ClassFileEntry> startOfPool = new ArrayList<>(entries.size());
193 final List<ClassFileEntry> finalSort = new ArrayList<>(entries.size());
194
195 for (final ClassFileEntry entry : entries) {
196 if (mustStartClassPool.contains(entry)) {
197 startOfPool.add(entry);
198 } else {
199 finalSort.add(entry);
200 }
201 }
202
203
204
205 indexCache = new HashMap<>(entries.size());
206 int index = 0;
207
208 entries.clear();
209
210 for (final ClassFileEntry entry : startOfPool) {
211 indexCache.put(entry, Integer.valueOf(index));
212
213 if (entry instanceof CPLong || entry instanceof CPDouble) {
214 entries.add(entry);
215 entries.add(entry);
216 index += 2;
217 } else {
218 entries.add(entry);
219 index += 1;
220 }
221 }
222
223 for (final ClassFileEntry entry : finalSort) {
224 indexCache.put(entry, Integer.valueOf(index));
225
226 if (entry instanceof CPLong || entry instanceof CPDouble) {
227 entries.add(entry);
228 entries.add(entry);
229 index += 2;
230 } else {
231 entries.add(entry);
232 index += 1;
233 }
234 }
235
236 }
237 }