io.github.dmlloyd.classfile.impl.SplitConstantPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdk-classfile-backport Show documentation
Show all versions of jdk-classfile-backport Show documentation
An unofficial backport of the JDK Classfile API to Java 17
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package io.github.dmlloyd.classfile.impl;
import io.github.dmlloyd.classfile.Attributes;
import io.github.dmlloyd.classfile.BootstrapMethodEntry;
import io.github.dmlloyd.classfile.ClassReader;
import io.github.dmlloyd.classfile.attribute.BootstrapMethodsAttribute;
import io.github.dmlloyd.classfile.constantpool.*;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.util.Arrays;
import java.util.List;
import static io.github.dmlloyd.classfile.constantpool.PoolEntry.*;
import static java.util.Objects.requireNonNull;
public final class SplitConstantPool implements ConstantPoolBuilder {
private final ClassReaderImpl parent;
private final int parentSize, parentBsmSize;
private int size, bsmSize;
private PoolEntry[] myEntries;
private BootstrapMethodEntryImpl[] myBsmEntries;
private boolean doneFullScan;
private EntryMap map;
private EntryMap bsmMap;
public SplitConstantPool() {
this.size = 1;
this.bsmSize = 0;
this.myEntries = new PoolEntry[1024];
this.myBsmEntries = new BootstrapMethodEntryImpl[8];
this.parent = null;
this.parentSize = 0;
this.parentBsmSize = 0;
this.doneFullScan = true;
}
public SplitConstantPool(ClassReader parent) {
this.parent = (ClassReaderImpl) parent;
this.parentSize = parent.size();
this.parentBsmSize = parent.bootstrapMethodCount();
this.size = parentSize;
this.bsmSize = parentBsmSize;
this.myEntries = new PoolEntry[8];
this.myBsmEntries = new BootstrapMethodEntryImpl[8];
this.doneFullScan = true;
}
@Override
public int size() {
return size;
}
@Override
public int bootstrapMethodCount() {
return bsmSize;
}
@Override
public PoolEntry entryByIndex(int index) {
if (index <= 0 || index >= size()) {
throw badCP(index);
}
PoolEntry pe = (index < parentSize)
? parent.entryByIndex(index)
: myEntries[index - parentSize];
if (pe == null) {
throw unusableCP(index);
}
return pe;
}
private static ConstantPoolException badCP(int index) {
return new ConstantPoolException("Bad CP index: " + index);
}
private static ConstantPoolException unusableCP(int index) {
return new ConstantPoolException("Unusable CP index: " + index);
}
@Override
public T entryByIndex(int index, Class cls) {
return ClassReaderImpl.checkType(entryByIndex(index), index, cls);
}
@Override
public BootstrapMethodEntryImpl bootstrapMethodEntry(int index) {
if (index < 0 || index >= bootstrapMethodCount()) {
throw new ConstantPoolException("Bad BSM index: " + index);
}
return (index < parentBsmSize)
? parent.bootstrapMethodEntry(index)
: myBsmEntries[index - parentBsmSize];
}
@Override
public boolean canWriteDirect(ConstantPool other) {
requireNonNull(other);
return this == other || parent == other;
}
public boolean writeBootstrapMethods(BufWriterImpl buf) {
if (bsmSize == 0)
return false;
int pos = buf.size();
if (parent != null && parentBsmSize != 0) {
parent.writeBootstrapMethods(buf);
for (int i = parentBsmSize; i < bsmSize; i++)
bootstrapMethodEntry(i).writeTo(buf);
int attrLen = buf.size() - pos;
buf.patchInt(pos + 2, attrLen - 6);
buf.patchU2(pos + 6, bsmSize);
}
else {
UnboundAttribute a
= new UnboundAttribute.AdHocAttribute<>(Attributes.bootstrapMethods()) {
@Override
public void writeBody(BufWriterImpl b) {
buf.writeU2(bsmSize);
for (int i = 0; i < bsmSize; i++)
bootstrapMethodEntry(i).writeTo(buf);
}
@Override
public Utf8Entry attributeName() {
return utf8Entry(Attributes.NAME_BOOTSTRAP_METHODS);
}
};
a.writeTo(buf);
}
return true;
}
void writeTo(BufWriterImpl buf) {
int writeFrom = 1;
if (size() >= 65536) {
throw new IllegalArgumentException(String.format("Constant pool is too large %d", size()));
}
buf.writeU2(size());
if (parent != null && buf.constantPool().canWriteDirect(this)) {
parent.writeConstantPoolEntries(buf);
writeFrom = parent.size();
}
for (int i = writeFrom; i < size(); ) {
var info = (AbstractPoolEntry) entryByIndex(i);
info.writeTo(buf);
i += info.width();
}
}
private EntryMap map() {
int parentSize = this.parentSize;
var map = this.map;
if (map == null) {
this.map = map = new EntryMap(Math.max(size, 1024), .75f);
// Doing a full scan here yields fall-off-the-cliff performance results,
// especially if we only need a few entries that are already
// inflated (such as attribute names).
// So we inflate the map with whatever we've got from the parent, and
// later, if we miss, we do a one-time full inflation before creating
// a new entry.
for (int i=1; i E internalAdd(E cpi) {
return internalAdd(cpi, cpi.hashCode());
}
private E internalAdd(E cpi, int hash) {
int newIndex = size-parentSize;
if (newIndex + 2 > myEntries.length) {
myEntries = Arrays.copyOf(myEntries, 2 * newIndex, PoolEntry[].class);
}
myEntries[newIndex] = cpi;
size += cpi.width();
map().put(hash, cpi.index());
return cpi;
}
private BootstrapMethodEntryImpl internalAdd(BootstrapMethodEntryImpl bsm, int hash) {
int newIndex = bsmSize-parentBsmSize;
if (newIndex + 2 > myBsmEntries.length) {
myBsmEntries = Arrays.copyOf(myBsmEntries, 2 * newIndex, BootstrapMethodEntryImpl[].class);
}
myBsmEntries[newIndex] = bsm;
bsmSize += 1;
bsmMap().put(hash, bsm.index);
return bsm;
}
private IntegerEntry findIntEntry(int val) {
int hash = AbstractPoolEntry.hash1(TAG_INTEGER, Integer.hashCode(val));
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_INTEGER
&& e instanceof AbstractPoolEntry.IntegerEntryImpl ce
&& ce.intValue() == val)
return ce;
}
if (!doneFullScan) {
fullScan();
return findIntEntry(val);
}
return null;
}
private LongEntry findLongEntry(long val) {
int hash = AbstractPoolEntry.hash1(TAG_LONG, Long.hashCode(val));
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_LONG
&& e instanceof AbstractPoolEntry.LongEntryImpl ce
&& ce.longValue() == val)
return ce;
}
if (!doneFullScan) {
fullScan();
return findLongEntry(val);
}
return null;
}
private FloatEntry findFloatEntry(float val) {
int hash = AbstractPoolEntry.hash1(TAG_FLOAT, Float.hashCode(val));
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_FLOAT
&& e instanceof AbstractPoolEntry.FloatEntryImpl ce
&& ce.floatValue() == val)
return ce;
}
if (!doneFullScan) {
fullScan();
return findFloatEntry(val);
}
return null;
}
private DoubleEntry findDoubleEntry(double val) {
int hash = AbstractPoolEntry.hash1(TAG_DOUBLE, Double.hashCode(val));
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_DOUBLE
&& e instanceof AbstractPoolEntry.DoubleEntryImpl ce
&& ce.doubleValue() == val)
return ce;
}
if (!doneFullScan) {
fullScan();
return findDoubleEntry(val);
}
return null;
}
private AbstractPoolEntry findEntry(int tag, T ref1) {
// invariant: canWriteDirect(ref1.constantPool())
int hash = AbstractPoolEntry.hash1(tag, ref1.index());
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == tag
&& e instanceof AbstractPoolEntry.AbstractRefEntry> re
&& re.ref1 == ref1)
return re;
}
if (!doneFullScan) {
fullScan();
return findEntry(tag, ref1);
}
return null;
}
private
AbstractPoolEntry findEntry(int tag, T ref1, U ref2) {
// invariant: canWriteDirect(ref1.constantPool()), canWriteDirect(ref2.constantPool())
int hash = AbstractPoolEntry.hash2(tag, ref1.index(), ref2.index());
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == tag
&& e instanceof AbstractPoolEntry.AbstractRefsEntry, ?> re
&& re.ref1 == ref1
&& re.ref2 == ref2) {
return re;
}
}
if (!doneFullScan) {
fullScan();
return findEntry(tag, ref1, ref2);
}
return null;
}
private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, String target) {
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1;
token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_UTF8
&& e instanceof AbstractPoolEntry.Utf8EntryImpl ce
&& target.equals(ce.stringValue()))
return ce;
}
if (!doneFullScan) {
fullScan();
return tryFindUtf8(hash, target);
}
return null;
}
private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, AbstractPoolEntry.Utf8EntryImpl target) {
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_UTF8
&& e instanceof AbstractPoolEntry.Utf8EntryImpl ce
&& target.equalsUtf8(ce))
return ce;
}
if (!doneFullScan) {
fullScan();
return tryFindUtf8(hash, target);
}
return null;
}
private AbstractPoolEntry.ClassEntryImpl tryFindClassOrInterface(int hash, ClassDesc cd) {
while (true) {
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_CLASS
&& e instanceof AbstractPoolEntry.ClassEntryImpl ce) {
var esym = ce.sym;
if (esym != null) {
if (cd.equals(esym)) {
return ce; // definite match
}
continue; // definite mismatch
}
// no symbol available
if (ce.ref1.equalsString(Util.toInternalName(cd))) {
// definite match, propagate symbol
ce.sym = cd;
return ce;
}
// definite mismatch
}
}
if (!doneFullScan) {
fullScan();
continue;
}
return null;
}
}
private AbstractPoolEntry.ClassEntryImpl classEntryForClassOrInterface(ClassDesc cd) {
var desc = cd.descriptorString();
int hash = AbstractPoolEntry.hashClassFromDescriptor(desc.hashCode());
var ce = tryFindClassOrInterface(hash, cd);
if (ce != null)
return ce;
String internalName = Util.toInternalName(cd);
var utfHash = internalName.hashCode();
var utf = tryFindUtf8(AbstractPoolEntry.hashString(utfHash), internalName);
if (utf == null)
utf = internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, internalName, utfHash));
return internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, utf, hash, cd));
}
private AbstractPoolEntry.ClassEntryImpl tryFindClassEntry(int hash, AbstractPoolEntry.Utf8EntryImpl utf8) {
EntryMap map = map();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map.getIndexByToken(token));
if (e.tag() == TAG_CLASS
&& e instanceof AbstractPoolEntry.ClassEntryImpl ce
&& ce.ref1.equalsUtf8(utf8))
return ce;
}
if (!doneFullScan) {
fullScan();
return tryFindClassEntry(hash, utf8);
}
return null;
}
@Override
public AbstractPoolEntry.Utf8EntryImpl utf8Entry(ClassDesc desc) {
var utf8 = utf8Entry(desc.descriptorString());
if (utf8.typeSym == null)
utf8.typeSym = desc;
return utf8;
}
@Override
public Utf8Entry utf8Entry(MethodTypeDesc desc) {
var utf8 = utf8Entry(desc.descriptorString());
if (utf8.typeSym == null)
utf8.typeSym = desc;
return utf8;
}
@Override
public AbstractPoolEntry.Utf8EntryImpl utf8Entry(String s) {
int contentHash = s.hashCode();
var ce = tryFindUtf8(AbstractPoolEntry.hashString(contentHash), s);
return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, s, contentHash)) : ce;
}
AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) {
AbstractPoolEntry.Utf8EntryImpl e = (AbstractPoolEntry.Utf8EntryImpl) entry;
if (e.constantPool == this || e.constantPool == parent)
return e;
AbstractPoolEntry.Utf8EntryImpl ce = tryFindUtf8(e.hashCode(), e);
return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, e)) : ce;
}
@Override
public AbstractPoolEntry.ClassEntryImpl classEntry(Utf8Entry nameEntry) {
var ne = maybeCloneUtf8Entry(nameEntry);
return classEntry(ne, AbstractPoolEntry.isArrayDescriptor(ne));
}
AbstractPoolEntry.ClassEntryImpl classEntry(AbstractPoolEntry.Utf8EntryImpl ne, boolean isArray) {
int hash = AbstractPoolEntry.hashClassFromUtf8(isArray, ne);
var e = tryFindClassEntry(hash, ne);
return e == null ? internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, ne, hash,
isArray && ne.typeSym instanceof ClassDesc cd ? cd : null)) : e;
}
@Override
public ClassEntry classEntry(ClassDesc cd) {
if (cd.isClassOrInterface()) { // implicit null check
return classEntryForClassOrInterface(cd);
}
if (cd.isArray()) {
return classEntry(utf8Entry(cd), true);
}
throw new IllegalArgumentException("Cannot be encoded as ClassEntry: " + cd.displayName());
}
AbstractPoolEntry.ClassEntryImpl cloneClassEntry(AbstractPoolEntry.ClassEntryImpl e) {
var ce = tryFindClassEntry(e.hashCode(), e.ref1);
if (ce != null) {
return ce;
}
var utf8 = maybeCloneUtf8Entry(e.ref1); // call order matters
return internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size,
utf8, e.hashCode(), e.sym));
}
@Override
public PackageEntry packageEntry(Utf8Entry nameEntry) {
AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry);
var e = (AbstractPoolEntry.PackageEntryImpl) findEntry(TAG_PACKAGE, ne);
return e == null ? internalAdd(new AbstractPoolEntry.PackageEntryImpl(this, size, ne)) : e;
}
@Override
public ModuleEntry moduleEntry(Utf8Entry nameEntry) {
AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry);
var e = (AbstractPoolEntry.ModuleEntryImpl) findEntry(TAG_MODULE, ne);
return e == null ? internalAdd(new AbstractPoolEntry.ModuleEntryImpl(this, size, ne)) : e;
}
@Override
public AbstractPoolEntry.NameAndTypeEntryImpl nameAndTypeEntry(Utf8Entry nameEntry, Utf8Entry typeEntry) {
AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry);
AbstractPoolEntry.Utf8EntryImpl te = maybeCloneUtf8Entry(typeEntry);
var e = (AbstractPoolEntry.NameAndTypeEntryImpl) findEntry(TAG_NAME_AND_TYPE, ne, te);
return e == null ? internalAdd(new AbstractPoolEntry.NameAndTypeEntryImpl(this, size, ne, te)) : e;
}
@Override
public FieldRefEntry fieldRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) {
var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner);
var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType);
var e = (AbstractPoolEntry.FieldRefEntryImpl) findEntry(TAG_FIELDREF, oe, ne);
return e == null ? internalAdd(new AbstractPoolEntry.FieldRefEntryImpl(this, size, oe, ne)) : e;
}
@Override
public MethodRefEntry methodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) {
var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner);
var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType);
var e = (AbstractPoolEntry.MethodRefEntryImpl) findEntry(TAG_METHODREF, oe, ne);
return e == null ? internalAdd(new AbstractPoolEntry.MethodRefEntryImpl(this, size, oe, ne)) : e;
}
@Override
public InterfaceMethodRefEntry interfaceMethodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) {
var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner);
var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType);
var e = (AbstractPoolEntry.InterfaceMethodRefEntryImpl) findEntry(TAG_INTERFACE_METHODREF, oe, ne);
return e == null ? internalAdd(new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, size, oe, ne)) : e;
}
@Override
public MethodTypeEntry methodTypeEntry(MethodTypeDesc descriptor) {
return methodTypeEntry(utf8Entry(descriptor));
}
@Override
public MethodTypeEntry methodTypeEntry(Utf8Entry descriptor) {
AbstractPoolEntry.Utf8EntryImpl de = maybeCloneUtf8Entry(descriptor);
var e = (AbstractPoolEntry.MethodTypeEntryImpl) findEntry(TAG_METHOD_TYPE, de);
return e == null ? internalAdd(new AbstractPoolEntry.MethodTypeEntryImpl(this, size, de)) : e;
}
@Override
public MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference) {
reference = AbstractPoolEntry.maybeClone(this, reference);
int hash = AbstractPoolEntry.hash2(TAG_METHOD_HANDLE, refKind, reference.index());
EntryMap map1 = map();
for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map1.getIndexByToken(token));
if (e.tag() == TAG_METHOD_HANDLE
&& e instanceof AbstractPoolEntry.MethodHandleEntryImpl ce
&& ce.kind() == refKind && ce.reference() == reference)
return ce;
}
if (!doneFullScan) {
fullScan();
return methodHandleEntry(refKind, reference);
}
return internalAdd(new AbstractPoolEntry.MethodHandleEntryImpl(this, size,
hash, refKind, (AbstractPoolEntry.AbstractMemberRefEntry) reference), hash);
}
@Override
public InvokeDynamicEntry invokeDynamicEntry(BootstrapMethodEntry bootstrapMethodEntry,
NameAndTypeEntry nameAndType) {
if (!canWriteDirect(bootstrapMethodEntry.constantPool()))
bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(),
bootstrapMethodEntry.arguments());
nameAndType = AbstractPoolEntry.maybeClone(this, nameAndType);
int hash = AbstractPoolEntry.hash2(TAG_INVOKE_DYNAMIC,
bootstrapMethodEntry.bsmIndex(), nameAndType.index());
EntryMap map1 = map();
for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map1.getIndexByToken(token));
if (e.tag() == TAG_INVOKE_DYNAMIC
&& e instanceof AbstractPoolEntry.InvokeDynamicEntryImpl ce
&& ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType)
return ce;
}
if (!doneFullScan) {
fullScan();
return invokeDynamicEntry(bootstrapMethodEntry, nameAndType);
}
AbstractPoolEntry.InvokeDynamicEntryImpl ce =
new AbstractPoolEntry.InvokeDynamicEntryImpl(this, size, hash,
(BootstrapMethodEntryImpl) bootstrapMethodEntry,
(AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType);
internalAdd(ce, hash);
return ce;
}
@Override
public ConstantDynamicEntry constantDynamicEntry(BootstrapMethodEntry bootstrapMethodEntry,
NameAndTypeEntry nameAndType) {
if (!canWriteDirect(bootstrapMethodEntry.constantPool()))
bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(),
bootstrapMethodEntry.arguments());
nameAndType = AbstractPoolEntry.maybeClone(this, nameAndType);
int hash = AbstractPoolEntry.hash2(TAG_DYNAMIC,
bootstrapMethodEntry.bsmIndex(), nameAndType.index());
EntryMap map1 = map();
for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) {
PoolEntry e = entryByIndex(map1.getIndexByToken(token));
if (e.tag() == TAG_DYNAMIC
&& e instanceof AbstractPoolEntry.ConstantDynamicEntryImpl ce
&& ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType)
return ce;
}
if (!doneFullScan) {
fullScan();
return constantDynamicEntry(bootstrapMethodEntry, nameAndType);
}
AbstractPoolEntry.ConstantDynamicEntryImpl ce =
new AbstractPoolEntry.ConstantDynamicEntryImpl(this, size, hash,
(BootstrapMethodEntryImpl) bootstrapMethodEntry,
(AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType);
internalAdd(ce, hash);
return ce;
}
@Override
public IntegerEntry intEntry(int value) {
var e = findIntEntry(value);
return e == null ? internalAdd(new AbstractPoolEntry.IntegerEntryImpl(this, size, value)) : e;
}
@Override
public FloatEntry floatEntry(float value) {
var e = findFloatEntry(value);
return e == null ? internalAdd(new AbstractPoolEntry.FloatEntryImpl(this, size, value)) : e;
}
@Override
public LongEntry longEntry(long value) {
var e = findLongEntry(value);
return e == null ? internalAdd(new AbstractPoolEntry.LongEntryImpl(this, size, value)) : e;
}
@Override
public DoubleEntry doubleEntry(double value) {
var e = findDoubleEntry(value);
return e == null ? internalAdd(new AbstractPoolEntry.DoubleEntryImpl(this, size, value)) : e;
}
@Override
public StringEntry stringEntry(Utf8Entry utf8) {
AbstractPoolEntry.Utf8EntryImpl ue = maybeCloneUtf8Entry(utf8);
var e = (AbstractPoolEntry.StringEntryImpl) findEntry(TAG_STRING, ue);
return e == null ? internalAdd(new AbstractPoolEntry.StringEntryImpl(this, size, ue)) : e;
}
@Override
public BootstrapMethodEntry bsmEntry(MethodHandleEntry methodReference,
List arguments) {
methodReference = AbstractPoolEntry.maybeClone(this, methodReference);
for (LoadableConstantEntry a : arguments) {
if (!canWriteDirect(a.constantPool())) {
// copy args list
LoadableConstantEntry[] arr = arguments.toArray(new LoadableConstantEntry[0]);
for (int i = 0; i < arr.length; i++)
arr[i] = AbstractPoolEntry.maybeClone(this, arr[i]);
arguments = List.of(arr);
break;
}
}
AbstractPoolEntry.MethodHandleEntryImpl mre = (AbstractPoolEntry.MethodHandleEntryImpl) methodReference;
int hash = BootstrapMethodEntryImpl.computeHashCode(mre, arguments);
EntryMap map = bsmMap();
for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) {
BootstrapMethodEntryImpl e = bootstrapMethodEntry(map.getIndexByToken(token));
if (e.bootstrapMethod() == mre && e.arguments().equals(arguments)) {
return e;
}
}
BootstrapMethodEntryImpl ne = new BootstrapMethodEntryImpl(this, bsmSize, hash, mre, arguments);
return internalAdd(ne, hash);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy