48826
|
1 |
/*
|
|
2 |
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
|
7 |
* published by the Free Software Foundation.
|
|
8 |
*
|
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
13 |
* accompanied this code).
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License version
|
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 |
*
|
|
19 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
20 |
* or visit www.oracle.com if you need additional information or have any
|
|
21 |
* questions.
|
|
22 |
*/
|
|
23 |
|
|
24 |
package jdk.experimental.bytecode;
|
|
25 |
|
|
26 |
import java.lang.invoke.MethodHandleInfo;
|
|
27 |
import java.util.ArrayList;
|
|
28 |
import java.util.List;
|
|
29 |
import java.util.Objects;
|
|
30 |
import java.util.function.Consumer;
|
|
31 |
import java.util.function.Function;
|
|
32 |
import java.util.function.ToIntBiFunction;
|
|
33 |
|
|
34 |
/**
|
|
35 |
* A helper for building and tracking constant pools whose entries are
|
|
36 |
* represented as byte arrays.
|
|
37 |
*
|
|
38 |
* @param <S> the type of the symbol representation
|
|
39 |
* @param <T> the type of type descriptors representation
|
|
40 |
*/
|
|
41 |
public class BytePoolHelper<S, T> implements PoolHelper<S, T, byte[]> {
|
|
42 |
|
|
43 |
GrowableByteBuffer pool = new GrowableByteBuffer();
|
|
44 |
GrowableByteBuffer bsm_attr = new GrowableByteBuffer();
|
|
45 |
//Map<PoolKey, PoolKey> indicesMap = new HashMap<>();
|
|
46 |
int currentIndex = 1;
|
|
47 |
int currentBsmIndex = 0;
|
|
48 |
|
|
49 |
KeyMap<PoolKey> entries = new KeyMap<>();
|
|
50 |
KeyMap<BsmKey> bootstraps = new KeyMap<>();
|
|
51 |
PoolKey key = new PoolKey();
|
|
52 |
BsmKey bsmKey = new BsmKey();
|
|
53 |
|
|
54 |
Function<S, String> symbolToString;
|
|
55 |
Function<T, String> typeToString;
|
|
56 |
|
|
57 |
public BytePoolHelper(Function<S, String> symbolToString, Function<T, String> typeToString) {
|
|
58 |
this.symbolToString = symbolToString;
|
|
59 |
this.typeToString = typeToString;
|
|
60 |
}
|
|
61 |
|
|
62 |
static class KeyMap<K extends AbstractKey<K>> {
|
|
63 |
|
|
64 |
@SuppressWarnings("unchecked")
|
|
65 |
K[] table = (K[])new AbstractKey<?>[0x10];
|
|
66 |
int nelems;
|
|
67 |
|
|
68 |
public void enter(K e) {
|
|
69 |
if (nelems * 3 >= (table.length - 1) * 2)
|
|
70 |
dble();
|
|
71 |
int hash = getIndex(e);
|
|
72 |
K old = table[hash];
|
|
73 |
if (old == null) {
|
|
74 |
nelems++;
|
|
75 |
}
|
|
76 |
e.next = old;
|
|
77 |
table[hash] = e;
|
|
78 |
}
|
|
79 |
|
|
80 |
protected K lookup(K other) {
|
|
81 |
K e = table[getIndex(other)];
|
|
82 |
while (e != null && !e.equals(other))
|
|
83 |
e = e.next;
|
|
84 |
return e;
|
|
85 |
}
|
|
86 |
|
|
87 |
/**
|
|
88 |
* Look for slot in the table.
|
|
89 |
* We use open addressing with double hashing.
|
|
90 |
*/
|
|
91 |
int getIndex(K e) {
|
|
92 |
int hashMask = table.length - 1;
|
|
93 |
int h = e.hashCode();
|
|
94 |
int i = h & hashMask;
|
|
95 |
// The expression below is always odd, so it is guaranteed
|
|
96 |
// to be mutually prime with table.length, a power of 2.
|
|
97 |
int x = hashMask - ((h + (h >> 16)) << 1);
|
|
98 |
for (; ; ) {
|
|
99 |
K e2 = table[i];
|
|
100 |
if (e2 == null)
|
|
101 |
return i;
|
|
102 |
else if (e.hash == e2.hash)
|
|
103 |
return i;
|
|
104 |
i = (i + x) & hashMask;
|
|
105 |
}
|
|
106 |
}
|
|
107 |
|
|
108 |
@SuppressWarnings("unchecked")
|
|
109 |
private void dble() {
|
|
110 |
K[] oldtable = table;
|
|
111 |
table = (K[])new AbstractKey<?>[oldtable.length * 2];
|
|
112 |
int n = 0;
|
|
113 |
for (int i = oldtable.length; --i >= 0; ) {
|
|
114 |
K e = oldtable[i];
|
|
115 |
if (e != null) {
|
|
116 |
table[getIndex(e)] = e;
|
|
117 |
n++;
|
|
118 |
}
|
|
119 |
}
|
|
120 |
// We don't need to update nelems for shared inherited scopes,
|
|
121 |
// since that gets handled by leave().
|
|
122 |
nelems = n;
|
|
123 |
}
|
|
124 |
}
|
|
125 |
|
|
126 |
public static abstract class AbstractKey<K extends AbstractKey<K>> {
|
|
127 |
int hash;
|
|
128 |
int index = -1;
|
|
129 |
K next;
|
|
130 |
|
|
131 |
abstract K dup();
|
|
132 |
|
|
133 |
public abstract boolean equals(Object o);
|
|
134 |
|
|
135 |
@Override
|
|
136 |
public int hashCode() {
|
|
137 |
return hash;
|
|
138 |
}
|
|
139 |
|
|
140 |
void at(int index) {
|
|
141 |
this.index = index;
|
|
142 |
}
|
|
143 |
}
|
|
144 |
|
|
145 |
public static class PoolKey extends AbstractKey<PoolKey> {
|
|
146 |
PoolTag tag;
|
|
147 |
Object o1;
|
|
148 |
Object o2;
|
|
149 |
Object o3;
|
|
150 |
Object o4;
|
|
151 |
int size = -1;
|
|
152 |
|
|
153 |
void setUtf8(CharSequence s) {
|
|
154 |
tag = PoolTag.CONSTANT_UTF8;
|
|
155 |
o1 = s;
|
|
156 |
size = 1;
|
|
157 |
hash = tag.tag | (s.hashCode() << 1);
|
|
158 |
}
|
|
159 |
|
|
160 |
void setClass(String clazz) {
|
|
161 |
tag = PoolTag.CONSTANT_CLASS;
|
|
162 |
o1 = clazz;
|
|
163 |
size = 1;
|
|
164 |
hash = tag.tag | (clazz.hashCode() << 1);
|
|
165 |
}
|
|
166 |
|
|
167 |
void setNameAndType(CharSequence name, String type) {
|
|
168 |
tag = PoolTag.CONSTANT_NAMEANDTYPE;
|
|
169 |
o1 = name;
|
|
170 |
o2 = type;
|
|
171 |
size = 2;
|
|
172 |
hash = tag.tag | ((name.hashCode() | type.hashCode()) << 1);
|
|
173 |
}
|
|
174 |
|
|
175 |
void setMemberRef(PoolTag poolTag, String owner, CharSequence name, String type) {
|
|
176 |
tag = poolTag;
|
|
177 |
o1 = owner;
|
|
178 |
o2 = name;
|
|
179 |
o3 = type;
|
|
180 |
size = 3;
|
|
181 |
hash = tag.tag | ((owner.hashCode() | name.hashCode() | type.hashCode()) << 1);
|
|
182 |
}
|
|
183 |
|
|
184 |
void setInvokeDynamic(int bsmIndex, CharSequence name, String type) {
|
|
185 |
tag = PoolTag.CONSTANT_INVOKEDYNAMIC;
|
|
186 |
o1 = bsmIndex;
|
|
187 |
o2 = name;
|
|
188 |
o3 = type;
|
|
189 |
size = 3;
|
|
190 |
hash = tag.tag | ((bsmIndex | name.hashCode() | type.hashCode()) << 1);
|
|
191 |
}
|
|
192 |
|
|
193 |
void setDynamicConstant(int bsmIndex, CharSequence name, String type) {
|
|
194 |
tag = PoolTag.CONSTANT_DYNAMIC;
|
|
195 |
o1 = bsmIndex;
|
|
196 |
o2 = name;
|
|
197 |
o3 = type;
|
|
198 |
size = 3;
|
|
199 |
hash = tag.tag | ((bsmIndex | name.hashCode() | type.hashCode()) << 1);
|
|
200 |
}
|
|
201 |
|
|
202 |
void setString(String s) {
|
|
203 |
tag = PoolTag.CONSTANT_STRING;
|
|
204 |
o1 = s;
|
|
205 |
size = 1;
|
|
206 |
hash = tag.tag | (s.hashCode() << 1);
|
|
207 |
}
|
|
208 |
|
|
209 |
void setInteger(Integer i) {
|
|
210 |
tag = PoolTag.CONSTANT_INTEGER;
|
|
211 |
o1 = i;
|
|
212 |
size = 1;
|
|
213 |
hash = tag.tag | (i.hashCode() << 1);
|
|
214 |
}
|
|
215 |
|
|
216 |
void setFloat(Float f) {
|
|
217 |
tag = PoolTag.CONSTANT_FLOAT;
|
|
218 |
o1 = f;
|
|
219 |
size = 1;
|
|
220 |
hash = tag.tag | (f.hashCode() << 1);
|
|
221 |
}
|
|
222 |
|
|
223 |
void setLong(Long l) {
|
|
224 |
tag = PoolTag.CONSTANT_LONG;
|
|
225 |
o1 = l;
|
|
226 |
size = 1;
|
|
227 |
hash = tag.tag | (l.hashCode() << 1);
|
|
228 |
}
|
|
229 |
|
|
230 |
void setDouble(Double d) {
|
|
231 |
tag = PoolTag.CONSTANT_DOUBLE;
|
|
232 |
o1 = d;
|
|
233 |
size = 1;
|
|
234 |
hash = tag.tag | (d.hashCode() << 1);
|
|
235 |
}
|
|
236 |
|
|
237 |
void setMethodType(String type) {
|
|
238 |
tag = PoolTag.CONSTANT_METHODTYPE;
|
|
239 |
o1 = type;
|
|
240 |
size = 1;
|
|
241 |
hash = tag.tag | (type.hashCode() << 1);
|
|
242 |
}
|
|
243 |
|
|
244 |
void setMethodHandle(int bsmKind, String owner, CharSequence name, String type) {
|
|
245 |
tag = PoolTag.CONSTANT_METHODHANDLE;
|
|
246 |
o1 = bsmKind;
|
|
247 |
o2 = owner;
|
|
248 |
o3 = name;
|
|
249 |
o4 = type;
|
|
250 |
size = 4;
|
|
251 |
hash = tag.tag | (bsmKind | owner.hashCode() | name.hashCode() | type.hashCode() << 1);
|
|
252 |
}
|
|
253 |
|
|
254 |
@Override
|
|
255 |
public boolean equals(Object obj) {
|
|
256 |
PoolKey that = (PoolKey) obj;
|
|
257 |
if (tag != that.tag) return false;
|
|
258 |
switch (size) {
|
|
259 |
case 1:
|
|
260 |
if (!o1.equals(that.o1)) {
|
|
261 |
return false;
|
|
262 |
}
|
|
263 |
break;
|
|
264 |
case 2:
|
|
265 |
if (!o2.equals(that.o2) || !o1.equals(that.o1)) {
|
|
266 |
return false;
|
|
267 |
}
|
|
268 |
break;
|
|
269 |
case 3:
|
|
270 |
if (!o3.equals(that.o3) || !o2.equals(that.o2) || !o1.equals(that.o1)) {
|
|
271 |
return false;
|
|
272 |
}
|
|
273 |
break;
|
|
274 |
case 4:
|
|
275 |
if (!o4.equals(that.o4) || !o3.equals(that.o3) || !o2.equals(that.o2) || !o1.equals(that.o1)) {
|
|
276 |
return false;
|
|
277 |
}
|
|
278 |
break;
|
|
279 |
}
|
|
280 |
return true;
|
|
281 |
}
|
|
282 |
|
|
283 |
PoolKey dup() {
|
|
284 |
PoolKey poolKey = new PoolKey();
|
|
285 |
poolKey.tag = tag;
|
|
286 |
poolKey.size = size;
|
|
287 |
poolKey.hash = hash;
|
|
288 |
poolKey.o1 = o1;
|
|
289 |
poolKey.o2 = o2;
|
|
290 |
poolKey.o3 = o3;
|
|
291 |
poolKey.o4 = o4;
|
|
292 |
return poolKey;
|
|
293 |
}
|
|
294 |
}
|
|
295 |
|
|
296 |
static class BsmKey extends AbstractKey<BsmKey> {
|
|
297 |
String bsmClass;
|
|
298 |
CharSequence bsmName;
|
|
299 |
String bsmType;
|
|
300 |
List<Integer> bsmArgs;
|
|
301 |
|
|
302 |
void set(String bsmClass, CharSequence bsmName, String bsmType, List<Integer> bsmArgs) {
|
|
303 |
this.bsmClass = bsmClass;
|
|
304 |
this.bsmName = bsmName;
|
|
305 |
this.bsmType = bsmType;
|
|
306 |
this.bsmArgs = bsmArgs;
|
|
307 |
hash = bsmClass.hashCode() | bsmName.hashCode() | bsmType.hashCode() | Objects.hash(bsmArgs);
|
|
308 |
}
|
|
309 |
|
|
310 |
BsmKey dup() {
|
|
311 |
BsmKey bsmKey = new BsmKey();
|
|
312 |
bsmKey.bsmClass = bsmClass;
|
|
313 |
bsmKey.bsmName = bsmName;
|
|
314 |
bsmKey.bsmType = bsmType;
|
|
315 |
bsmKey.bsmArgs = bsmArgs;
|
|
316 |
bsmKey.hash = hash;
|
|
317 |
return bsmKey;
|
|
318 |
}
|
|
319 |
|
|
320 |
@Override
|
|
321 |
public boolean equals(Object obj) {
|
|
322 |
if (obj instanceof BsmKey) {
|
|
323 |
BsmKey that = (BsmKey)obj;
|
|
324 |
return Objects.equals(bsmClass, that.bsmClass) &&
|
|
325 |
Objects.equals(bsmName, that.bsmName) &&
|
|
326 |
Objects.equals(bsmType, that.bsmType) &&
|
|
327 |
Objects.deepEquals(bsmArgs, that.bsmArgs);
|
|
328 |
} else {
|
|
329 |
return false;
|
|
330 |
}
|
|
331 |
}
|
|
332 |
}
|
|
333 |
|
|
334 |
@Override
|
|
335 |
public int putClass(S symbol) {
|
|
336 |
return putClassInternal(symbolToString.apply(symbol));
|
|
337 |
}
|
|
338 |
|
|
339 |
private int putClassInternal(String symbol) {
|
|
340 |
key.setClass(symbol);
|
|
341 |
PoolKey poolKey = entries.lookup(key);
|
|
342 |
if (poolKey == null) {
|
|
343 |
poolKey = key.dup();
|
|
344 |
int utf8_idx = putUtf8(symbol);
|
|
345 |
poolKey.at(currentIndex++);
|
|
346 |
entries.enter(poolKey);
|
|
347 |
pool.writeByte(PoolTag.CONSTANT_CLASS.tag);
|
|
348 |
pool.writeChar(utf8_idx);
|
|
349 |
}
|
|
350 |
return poolKey.index;
|
|
351 |
}
|
|
352 |
|
|
353 |
@Override
|
|
354 |
public int putFieldRef(S owner, CharSequence name, T type) {
|
|
355 |
return putMemberRef(PoolTag.CONSTANT_FIELDREF, owner, name, type);
|
|
356 |
}
|
|
357 |
|
|
358 |
@Override
|
|
359 |
public int putMethodRef(S owner, CharSequence name, T type, boolean isInterface) {
|
|
360 |
return putMemberRef(isInterface ? PoolTag.CONSTANT_INTERFACEMETHODREF : PoolTag.CONSTANT_METHODREF,
|
|
361 |
owner, name, type);
|
|
362 |
}
|
|
363 |
|
|
364 |
int putMemberRef(PoolTag poolTag, S owner, CharSequence name, T type) {
|
|
365 |
return putMemberRefInternal(poolTag, symbolToString.apply(owner), name, typeToString.apply(type));
|
|
366 |
}
|
|
367 |
|
|
368 |
int putMemberRefInternal(PoolTag poolTag, String owner, CharSequence name, String type) {
|
|
369 |
key.setMemberRef(poolTag, owner, name, type);
|
|
370 |
PoolKey poolKey = entries.lookup(key);
|
|
371 |
if (poolKey == null) {
|
|
372 |
poolKey = key.dup();
|
|
373 |
int owner_idx = putClassInternal(owner);
|
|
374 |
int nameAndType_idx = putNameAndType(name, type);
|
|
375 |
poolKey.at(currentIndex++);
|
|
376 |
entries.enter(poolKey);
|
|
377 |
pool.writeByte(poolTag.tag);
|
|
378 |
pool.writeChar(owner_idx);
|
|
379 |
pool.writeChar(nameAndType_idx);
|
|
380 |
}
|
|
381 |
return poolKey.index;
|
|
382 |
}
|
|
383 |
|
|
384 |
@Override
|
|
385 |
public int putInt(int i) {
|
|
386 |
key.setInteger(i);
|
|
387 |
PoolKey poolKey = entries.lookup(key);
|
|
388 |
if (poolKey == null) {
|
|
389 |
poolKey = key.dup();
|
|
390 |
poolKey.at(currentIndex++);
|
|
391 |
entries.enter(poolKey);
|
|
392 |
pool.writeByte(PoolTag.CONSTANT_INTEGER.tag);
|
|
393 |
pool.writeInt(i);
|
|
394 |
}
|
|
395 |
return poolKey.index;
|
|
396 |
}
|
|
397 |
|
|
398 |
@Override
|
|
399 |
public int putFloat(float f) {
|
|
400 |
key.setFloat(f);
|
|
401 |
PoolKey poolKey = entries.lookup(key);
|
|
402 |
if (poolKey == null) {
|
|
403 |
poolKey = key.dup();
|
|
404 |
poolKey.at(currentIndex++);
|
|
405 |
entries.enter(poolKey);
|
|
406 |
pool.writeByte(PoolTag.CONSTANT_FLOAT.tag);
|
|
407 |
pool.writeFloat(f);
|
|
408 |
}
|
|
409 |
return poolKey.index;
|
|
410 |
}
|
|
411 |
|
|
412 |
@Override
|
|
413 |
public int putLong(long l) {
|
|
414 |
key.setLong(l);
|
|
415 |
PoolKey poolKey = entries.lookup(key);
|
|
416 |
if (poolKey == null) {
|
|
417 |
poolKey = key.dup();
|
|
418 |
poolKey.at(currentIndex++);
|
|
419 |
entries.enter(poolKey);
|
|
420 |
pool.writeByte(PoolTag.CONSTANT_LONG.tag);
|
|
421 |
pool.writeLong(l);
|
|
422 |
currentIndex++;
|
|
423 |
}
|
|
424 |
return poolKey.index;
|
|
425 |
}
|
|
426 |
|
|
427 |
@Override
|
|
428 |
public int putDouble(double d) {
|
|
429 |
key.setDouble(d);
|
|
430 |
PoolKey poolKey = entries.lookup(key);
|
|
431 |
if (poolKey == null) {
|
|
432 |
poolKey = key.dup();
|
|
433 |
poolKey.at(currentIndex++);
|
|
434 |
entries.enter(poolKey);
|
|
435 |
pool.writeByte(PoolTag.CONSTANT_DOUBLE.tag);
|
|
436 |
pool.writeDouble(d);
|
|
437 |
currentIndex++;
|
|
438 |
}
|
|
439 |
return poolKey.index;
|
|
440 |
}
|
|
441 |
|
|
442 |
|
|
443 |
@Override
|
|
444 |
public int putInvokeDynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
|
|
445 |
return putInvokeDynamicInternal(invokedName, typeToString.apply(invokedType), symbolToString.apply(bsmClass), bsmName, typeToString.apply(bsmType), staticArgs);
|
|
446 |
}
|
|
447 |
|
|
448 |
@Override
|
|
449 |
public int putDynamicConstant(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
|
|
450 |
return putDynamicConstantInternal(constName, typeToString.apply(constType), symbolToString.apply(bsmClass), bsmName, typeToString.apply(bsmType), staticArgs);
|
|
451 |
}
|
|
452 |
|
|
453 |
private int putInvokeDynamicInternal(CharSequence invokedName, String invokedType, String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
|
|
454 |
int bsmIndex = putBsmInternal(bsmClass, bsmName, bsmType, staticArgs);
|
|
455 |
key.setInvokeDynamic(bsmIndex, invokedName, invokedType);
|
|
456 |
PoolKey poolKey = entries.lookup(key);
|
|
457 |
if (poolKey == null) {
|
|
458 |
poolKey = key.dup();
|
|
459 |
int nameAndType_idx = putNameAndType(invokedName, invokedType);
|
|
460 |
poolKey.at(currentIndex++);
|
|
461 |
entries.enter(poolKey);
|
|
462 |
pool.writeByte(PoolTag.CONSTANT_INVOKEDYNAMIC.tag);
|
|
463 |
pool.writeChar(bsmIndex);
|
|
464 |
pool.writeChar(nameAndType_idx);
|
|
465 |
}
|
|
466 |
return poolKey.index;
|
|
467 |
}
|
|
468 |
|
|
469 |
private int putDynamicConstantInternal(CharSequence constName, String constType, String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
|
|
470 |
int bsmIndex = putBsmInternal(bsmClass, bsmName, bsmType, staticArgs);
|
|
471 |
key.setDynamicConstant(bsmIndex, constName, constType);
|
|
472 |
PoolKey poolKey = entries.lookup(key);
|
|
473 |
if (poolKey == null) {
|
|
474 |
poolKey = key.dup();
|
|
475 |
int nameAndType_idx = putNameAndType(constName, constType);
|
|
476 |
poolKey.at(currentIndex++);
|
|
477 |
entries.enter(poolKey);
|
|
478 |
pool.writeByte(PoolTag.CONSTANT_DYNAMIC.tag);
|
|
479 |
pool.writeChar(bsmIndex);
|
|
480 |
pool.writeChar(nameAndType_idx);
|
|
481 |
}
|
|
482 |
return poolKey.index;
|
|
483 |
}
|
|
484 |
|
|
485 |
private int putBsmInternal(String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
|
|
486 |
ByteStaticArgListBuilder staticArgsBuilder = new ByteStaticArgListBuilder();
|
|
487 |
staticArgs.accept(staticArgsBuilder);
|
|
488 |
List<Integer> static_idxs = staticArgsBuilder.indexes;
|
|
489 |
bsmKey.set(bsmClass, bsmName, bsmType, static_idxs);
|
|
490 |
BsmKey poolKey = bootstraps.lookup(bsmKey);
|
|
491 |
if (poolKey == null) {
|
|
492 |
poolKey = bsmKey.dup();
|
|
493 |
int bsm_ref = putHandleInternal(MethodHandleInfo.REF_invokeStatic, bsmClass, bsmName, bsmType);
|
|
494 |
poolKey.at(currentBsmIndex++);
|
|
495 |
bootstraps.enter(poolKey);
|
|
496 |
bsm_attr.writeChar(bsm_ref);
|
|
497 |
bsm_attr.writeChar(static_idxs.size());
|
|
498 |
for (int i : static_idxs) {
|
|
499 |
bsm_attr.writeChar(i);
|
|
500 |
}
|
|
501 |
}
|
|
502 |
return poolKey.index;
|
|
503 |
}
|
|
504 |
//where
|
|
505 |
class ByteStaticArgListBuilder implements StaticArgListBuilder<S, T, byte[]> {
|
|
506 |
|
|
507 |
List<Integer> indexes = new ArrayList<>();
|
|
508 |
|
|
509 |
public ByteStaticArgListBuilder add(int i) {
|
|
510 |
indexes.add(putInt(i));
|
|
511 |
return this;
|
|
512 |
}
|
|
513 |
public ByteStaticArgListBuilder add(float f) {
|
|
514 |
indexes.add(putFloat(f));
|
|
515 |
return this;
|
|
516 |
}
|
|
517 |
public ByteStaticArgListBuilder add(long l) {
|
|
518 |
indexes.add(putLong(l));
|
|
519 |
return this;
|
|
520 |
}
|
|
521 |
public ByteStaticArgListBuilder add(double d) {
|
|
522 |
indexes.add(putDouble(d));
|
|
523 |
return this;
|
|
524 |
}
|
|
525 |
public ByteStaticArgListBuilder add(String s) {
|
|
526 |
indexes.add(putString(s));
|
|
527 |
return this;
|
|
528 |
}
|
|
529 |
@Override
|
|
530 |
public StaticArgListBuilder<S, T, byte[]> add(int refKind, S owner, CharSequence name, T type) {
|
|
531 |
indexes.add(putHandle(refKind, owner, name, type));
|
|
532 |
return this;
|
|
533 |
}
|
|
534 |
public <Z> ByteStaticArgListBuilder add(Z z, ToIntBiFunction<PoolHelper<S, T, byte[]>, Z> poolFunc) {
|
|
535 |
indexes.add(poolFunc.applyAsInt(BytePoolHelper.this, z));
|
|
536 |
return this;
|
|
537 |
}
|
|
538 |
public ByteStaticArgListBuilder add(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
|
|
539 |
indexes.add(putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs));
|
|
540 |
return this;
|
|
541 |
}
|
|
542 |
}
|
|
543 |
|
|
544 |
@Override
|
|
545 |
public int putMethodType(T s) {
|
|
546 |
return putMethodTypeInternal(typeToString.apply(s));
|
|
547 |
}
|
|
548 |
|
|
549 |
private int putMethodTypeInternal(String s) {
|
|
550 |
key.setMethodType(s);
|
|
551 |
PoolKey poolKey = entries.lookup(key);
|
|
552 |
if (poolKey == null) {
|
|
553 |
poolKey = key.dup();
|
|
554 |
int desc_idx = putUtf8(s);
|
|
555 |
poolKey.at(currentIndex++);
|
|
556 |
entries.enter(poolKey);
|
|
557 |
pool.writeByte(PoolTag.CONSTANT_METHODTYPE.tag);
|
|
558 |
pool.writeChar(desc_idx);
|
|
559 |
}
|
|
560 |
return poolKey.index;
|
|
561 |
}
|
|
562 |
|
|
563 |
@Override
|
|
564 |
public int putHandle(int refKind, S owner, CharSequence name, T type) {
|
|
565 |
return putHandleInternal(refKind, symbolToString.apply(owner), name, typeToString.apply(type));
|
|
566 |
}
|
|
567 |
|
|
568 |
private int putHandleInternal(int refKind, String owner, CharSequence name, String type) {
|
|
569 |
key.setMethodHandle(refKind, owner, name, type);
|
|
570 |
PoolKey poolKey = entries.lookup(key);
|
|
571 |
if (poolKey == null) {
|
|
572 |
poolKey = key.dup();
|
|
573 |
int ref_idx = putMemberRefInternal(fromKind(refKind), owner, name, type);
|
|
574 |
poolKey.at(currentIndex++);
|
|
575 |
entries.enter(poolKey);
|
|
576 |
pool.writeByte(PoolTag.CONSTANT_METHODHANDLE.tag);
|
|
577 |
pool.writeByte(refKind);
|
|
578 |
pool.writeChar(ref_idx);
|
|
579 |
}
|
|
580 |
return poolKey.index;
|
|
581 |
}
|
|
582 |
|
|
583 |
PoolTag fromKind(int bsmKind) {
|
|
584 |
switch (bsmKind) {
|
|
585 |
case 1: // REF_getField
|
|
586 |
case 2: // REF_getStatic
|
|
587 |
case 3: // REF_putField
|
|
588 |
case 4: // REF_putStatic
|
|
589 |
return PoolTag.CONSTANT_FIELDREF;
|
|
590 |
case 5: // REF_invokeVirtual
|
|
591 |
case 6: // REF_invokeStatic
|
|
592 |
case 7: // REF_invokeSpecial
|
|
593 |
case 8: // REF_newInvokeSpecial
|
|
594 |
return PoolTag.CONSTANT_METHODREF;
|
|
595 |
case 9: // REF_invokeInterface
|
|
596 |
return PoolTag.CONSTANT_INTERFACEMETHODREF;
|
|
597 |
default:
|
|
598 |
throw new IllegalStateException();
|
|
599 |
}
|
|
600 |
}
|
|
601 |
|
|
602 |
@Override
|
|
603 |
public int putType(T s) {
|
|
604 |
return putUtf8(typeToString.apply(s));
|
|
605 |
}
|
|
606 |
|
|
607 |
public int putUtf8(CharSequence s) {
|
|
608 |
key.setUtf8(s);
|
|
609 |
PoolKey poolKey = entries.lookup(key);
|
|
610 |
if (poolKey == null) {
|
|
611 |
poolKey = key.dup();
|
|
612 |
poolKey.at(currentIndex++);
|
|
613 |
entries.enter(poolKey);
|
|
614 |
pool.writeByte(PoolTag.CONSTANT_UTF8.tag);
|
|
615 |
putUTF8Internal(s);
|
|
616 |
}
|
|
617 |
return poolKey.index;
|
|
618 |
}
|
|
619 |
|
|
620 |
/**
|
|
621 |
* Puts an UTF8 string into this byte vector. The byte vector is
|
|
622 |
* automatically enlarged if necessary.
|
|
623 |
*
|
|
624 |
* @param s a String whose UTF8 encoded length must be less than 65536.
|
|
625 |
* @return this byte vector.
|
|
626 |
*/
|
|
627 |
void putUTF8Internal(final CharSequence s) {
|
|
628 |
int charLength = s.length();
|
|
629 |
if (charLength > 65535) {
|
|
630 |
throw new IllegalArgumentException();
|
|
631 |
}
|
|
632 |
// optimistic algorithm: instead of computing the byte length and then
|
|
633 |
// serializing the string (which requires two loops), we assume the byte
|
|
634 |
// length is equal to char length (which is the most frequent case), and
|
|
635 |
// we start serializing the string right away. During the serialization,
|
|
636 |
// if we find that this assumption is wrong, we continue with the
|
|
637 |
// general method.
|
|
638 |
pool.writeChar(charLength);
|
|
639 |
for (int i = 0; i < charLength; ++i) {
|
|
640 |
char c = s.charAt(i);
|
|
641 |
if (c >= '\001' && c <= '\177') {
|
|
642 |
pool.writeByte((byte) c);
|
|
643 |
} else {
|
|
644 |
encodeUTF8(s, i, 65535);
|
|
645 |
break;
|
|
646 |
}
|
|
647 |
}
|
|
648 |
}
|
|
649 |
|
|
650 |
/**
|
|
651 |
* Puts an UTF8 string into this byte vector. The byte vector is
|
|
652 |
* automatically enlarged if necessary. The string length is encoded in two
|
|
653 |
* bytes before the encoded characters, if there is space for that (i.e. if
|
|
654 |
* this.length - i - 2 >= 0).
|
|
655 |
*
|
|
656 |
* @param s the String to encode.
|
|
657 |
* @param i the index of the first character to encode. The previous
|
|
658 |
* characters are supposed to have already been encoded, using
|
|
659 |
* only one byte per character.
|
|
660 |
* @param maxByteLength the maximum byte length of the encoded string, including the
|
|
661 |
* already encoded characters.
|
|
662 |
* @return this byte vector.
|
|
663 |
*/
|
|
664 |
void encodeUTF8(final CharSequence s, int i, int maxByteLength) {
|
|
665 |
int charLength = s.length();
|
|
666 |
int byteLength = i;
|
|
667 |
char c;
|
|
668 |
for (int j = i; j < charLength; ++j) {
|
|
669 |
c = s.charAt(j);
|
|
670 |
if (c >= '\001' && c <= '\177') {
|
|
671 |
byteLength++;
|
|
672 |
} else if (c > '\u07FF') {
|
|
673 |
byteLength += 3;
|
|
674 |
} else {
|
|
675 |
byteLength += 2;
|
|
676 |
}
|
|
677 |
}
|
|
678 |
if (byteLength > maxByteLength) {
|
|
679 |
throw new IllegalArgumentException();
|
|
680 |
}
|
|
681 |
int byteLengthFinal = byteLength;
|
|
682 |
pool.withOffset(pool.offset - i - 2, buf -> buf.writeChar(byteLengthFinal));
|
|
683 |
for (int j = i; j < charLength; ++j) {
|
|
684 |
c = s.charAt(j);
|
|
685 |
if (c >= '\001' && c <= '\177') {
|
|
686 |
pool.writeChar((byte) c);
|
|
687 |
} else if (c > '\u07FF') {
|
|
688 |
pool.writeChar((byte) (0xE0 | c >> 12 & 0xF));
|
|
689 |
pool.writeChar((byte) (0x80 | c >> 6 & 0x3F));
|
|
690 |
pool.writeChar((byte) (0x80 | c & 0x3F));
|
|
691 |
} else {
|
|
692 |
pool.writeChar((byte) (0xC0 | c >> 6 & 0x1F));
|
|
693 |
pool.writeChar((byte) (0x80 | c & 0x3F));
|
|
694 |
}
|
|
695 |
}
|
|
696 |
}
|
|
697 |
|
|
698 |
@Override
|
|
699 |
public int putString(String s) {
|
|
700 |
key.setString(s);
|
|
701 |
PoolKey poolKey = entries.lookup(key);
|
|
702 |
if (poolKey == null) {
|
|
703 |
poolKey = key.dup();
|
|
704 |
int utf8_index = putUtf8(s);
|
|
705 |
poolKey.at(currentIndex++);
|
|
706 |
entries.enter(poolKey);
|
|
707 |
pool.writeByte(PoolTag.CONSTANT_STRING.tag);
|
|
708 |
pool.writeChar(utf8_index);
|
|
709 |
}
|
|
710 |
return poolKey.index;
|
|
711 |
}
|
|
712 |
|
|
713 |
int putNameAndType(CharSequence name, String type) {
|
|
714 |
key.setNameAndType(name, type);
|
|
715 |
PoolKey poolKey = entries.lookup(key);
|
|
716 |
if (poolKey == null) {
|
|
717 |
poolKey = key.dup();
|
|
718 |
int name_idx = putUtf8(name);
|
|
719 |
int type_idx = putUtf8(type);
|
|
720 |
poolKey.at(currentIndex++);
|
|
721 |
entries.enter(poolKey);
|
|
722 |
pool.writeByte(PoolTag.CONSTANT_NAMEANDTYPE.tag);
|
|
723 |
pool.writeChar(name_idx);
|
|
724 |
pool.writeChar(type_idx);
|
|
725 |
}
|
|
726 |
return poolKey.index;
|
|
727 |
}
|
|
728 |
|
|
729 |
@Override
|
|
730 |
public int size() {
|
|
731 |
return currentIndex - 1;
|
|
732 |
}
|
|
733 |
|
|
734 |
@Override
|
|
735 |
public byte[] entries() {
|
|
736 |
return pool.bytes();
|
|
737 |
}
|
|
738 |
|
|
739 |
<Z extends ClassBuilder<S, T, Z>> void addAttributes(ClassBuilder<S , T, Z> cb) {
|
|
740 |
if (currentBsmIndex > 0) {
|
|
741 |
GrowableByteBuffer bsmAttrBuf = new GrowableByteBuffer();
|
|
742 |
bsmAttrBuf.writeChar(currentBsmIndex);
|
|
743 |
bsmAttrBuf.writeBytes(bsm_attr);
|
|
744 |
cb.withAttribute("BootstrapMethods", bsmAttrBuf.bytes());
|
|
745 |
}
|
|
746 |
}
|
|
747 |
}
|