mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8306842: Classfile API performance improvements
Reviewed-by: redestad
This commit is contained in:
parent
95da499ef2
commit
f4f5542f8d
28 changed files with 499 additions and 206 deletions
|
@ -36,6 +36,7 @@ import jdk.internal.classfile.constantpool.Utf8Entry;
|
|||
import jdk.internal.classfile.impl.BoundAttribute;
|
||||
import jdk.internal.classfile.impl.TemporaryConstantPool;
|
||||
import jdk.internal.classfile.impl.UnboundAttribute;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
||||
/**
|
||||
* Models the {@code EnclosingMethod} attribute {@jvms 4.7.7}, which can appear
|
||||
|
@ -81,7 +82,7 @@ public sealed interface EnclosingMethodAttribute
|
|||
* immediately enclosed by a method or constructor}
|
||||
*/
|
||||
default Optional<MethodTypeDesc> enclosingMethodTypeSymbol() {
|
||||
return enclosingMethodType().map(n -> MethodTypeDesc.ofDescriptor(n.stringValue()));
|
||||
return enclosingMethod().map(Util::methodTypeSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
package jdk.internal.classfile.constantpool;
|
||||
|
||||
import jdk.internal.classfile.TypeKind;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
|
||||
|
@ -50,7 +50,7 @@ public sealed interface ConstantDynamicEntry
|
|||
default DynamicConstantDesc<?> asSymbol() {
|
||||
return DynamicConstantDesc.ofNamed(bootstrap().bootstrapMethod().asSymbol(),
|
||||
name().stringValue(),
|
||||
ClassDesc.ofDescriptor(type().stringValue()),
|
||||
Util.fieldTypeSymbol(nameAndType()),
|
||||
bootstrap().arguments().stream()
|
||||
.map(LoadableConstantEntry::constantValue)
|
||||
.toArray(ConstantDesc[]::new));
|
||||
|
|
|
@ -43,6 +43,8 @@ import jdk.internal.classfile.impl.Options;
|
|||
import java.lang.constant.ModuleDesc;
|
||||
import java.lang.constant.PackageDesc;
|
||||
import jdk.internal.classfile.WritableElement;
|
||||
import jdk.internal.classfile.impl.AbstractPoolEntry.ClassEntryImpl;
|
||||
import jdk.internal.classfile.impl.AbstractPoolEntry.NameAndTypeEntryImpl;
|
||||
import jdk.internal.classfile.impl.SplitConstantPool;
|
||||
import jdk.internal.classfile.impl.TemporaryConstantPool;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
@ -160,7 +162,9 @@ public sealed interface ConstantPoolBuilder
|
|||
if (classDesc.isPrimitive()) {
|
||||
throw new IllegalArgumentException("Cannot be encoded as ClassEntry: " + classDesc.displayName());
|
||||
}
|
||||
return classEntry(utf8Entry(classDesc.isArray() ? classDesc.descriptorString() : Util.toInternalName(classDesc)));
|
||||
ClassEntryImpl ret = (ClassEntryImpl)classEntry(utf8Entry(classDesc.isArray() ? classDesc.descriptorString() : Util.toInternalName(classDesc)));
|
||||
ret.sym = classDesc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -233,7 +237,9 @@ public sealed interface ConstantPoolBuilder
|
|||
* @param type the symbolic descriptor for a field type
|
||||
*/
|
||||
default NameAndTypeEntry nameAndTypeEntry(String name, ClassDesc type) {
|
||||
return nameAndTypeEntry(utf8Entry(name), utf8Entry(type.descriptorString()));
|
||||
var ret = (NameAndTypeEntryImpl)nameAndTypeEntry(utf8Entry(name), utf8Entry(type.descriptorString()));
|
||||
ret.typeSym = type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,7 +252,9 @@ public sealed interface ConstantPoolBuilder
|
|||
* @param type the symbolic descriptor for a method type
|
||||
*/
|
||||
default NameAndTypeEntry nameAndTypeEntry(String name, MethodTypeDesc type) {
|
||||
return nameAndTypeEntry(utf8Entry(name), utf8Entry(type.descriptorString()));
|
||||
var ret = (NameAndTypeEntryImpl)nameAndTypeEntry(utf8Entry(name), utf8Entry(type.descriptorString()));
|
||||
ret.typeSym = type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,9 +26,9 @@ package jdk.internal.classfile.constantpool;
|
|||
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.DynamicCallSiteDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
|
||||
import jdk.internal.classfile.impl.AbstractPoolEntry;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
||||
/**
|
||||
* Models a constant pool entry for a dynamic call site.
|
||||
|
@ -43,7 +43,7 @@ public sealed interface InvokeDynamicEntry
|
|||
default DynamicCallSiteDesc asSymbol() {
|
||||
return DynamicCallSiteDesc.of(bootstrap().bootstrapMethod().asSymbol(),
|
||||
name().stringValue(),
|
||||
MethodTypeDesc.ofDescriptor(type().stringValue()),
|
||||
Util.methodTypeSymbol(nameAndType()),
|
||||
bootstrap().arguments().stream()
|
||||
.map(LoadableConstantEntry::constantValue)
|
||||
.toArray(ConstantDesc[]::new));
|
||||
|
|
|
@ -50,7 +50,5 @@ public sealed interface MethodTypeEntry
|
|||
/**
|
||||
* {@return a symbolic descriptor for the method type}
|
||||
*/
|
||||
default MethodTypeDesc asSymbol() {
|
||||
return MethodTypeDesc.ofDescriptor(descriptor().stringValue());
|
||||
}
|
||||
MethodTypeDesc asSymbol();
|
||||
}
|
||||
|
|
|
@ -424,7 +424,7 @@ public abstract sealed class AbstractInstruction
|
|||
|
||||
@Override
|
||||
public int count() {
|
||||
return Util.parameterSlots(type().stringValue());
|
||||
return Util.parameterSlots(Util.methodTypeSymbol(method().nameAndType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1059,7 +1059,7 @@ public abstract sealed class AbstractInstruction
|
|||
@Override
|
||||
public int count() {
|
||||
return op == Opcode.INVOKEINTERFACE
|
||||
? Util.parameterSlots(methodEntry.nameAndType().type().stringValue()) + 1
|
||||
? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.nameAndType())) + 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.lang.constant.*;
|
||||
import java.lang.invoke.TypeDescriptor;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -163,6 +164,10 @@ public abstract sealed class AbstractPoolEntry {
|
|||
}
|
||||
|
||||
Utf8EntryImpl(ConstantPool cpm, int index, String s) {
|
||||
this(cpm, index, s, hashString(s.hashCode()));
|
||||
}
|
||||
|
||||
Utf8EntryImpl(ConstantPool cpm, int index, String s, int hash) {
|
||||
super(cpm, Classfile.TAG_UTF8, index, 0);
|
||||
this.rawBytes = null;
|
||||
this.offset = 0;
|
||||
|
@ -170,7 +175,7 @@ public abstract sealed class AbstractPoolEntry {
|
|||
this.state = State.STRING;
|
||||
this.stringValue = s;
|
||||
this.charLen = s.length();
|
||||
this.hash = hashString(s.hashCode());
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
Utf8EntryImpl(ConstantPool cpm, int index, Utf8EntryImpl u) {
|
||||
|
@ -556,18 +561,30 @@ public abstract sealed class AbstractPoolEntry {
|
|||
|
||||
public static final class ClassEntryImpl extends AbstractNamedEntry implements ClassEntry {
|
||||
|
||||
public ClassDesc sym = null;
|
||||
|
||||
ClassEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) {
|
||||
super(cpm, Classfile.TAG_CLASS, index, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassEntry clone(ConstantPoolBuilder cp) {
|
||||
return cp.canWriteDirect(constantPool) ? this : cp.classEntry(ref1);
|
||||
if (cp.canWriteDirect(constantPool)) {
|
||||
return this;
|
||||
} else {
|
||||
ClassEntryImpl ret = (ClassEntryImpl)cp.classEntry(ref1);
|
||||
ret.sym = sym;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc asSymbol() {
|
||||
return Util.toClassDesc(asInternalName());
|
||||
var sym = this.sym;
|
||||
if (sym != null) {
|
||||
return sym;
|
||||
}
|
||||
return this.sym = Util.toClassDesc(asInternalName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -637,6 +654,8 @@ public abstract sealed class AbstractPoolEntry {
|
|||
public static final class NameAndTypeEntryImpl extends AbstractRefsEntry<Utf8EntryImpl, Utf8EntryImpl>
|
||||
implements NameAndTypeEntry {
|
||||
|
||||
public TypeDescriptor typeSym = null;
|
||||
|
||||
NameAndTypeEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name, Utf8EntryImpl type) {
|
||||
super(cpm, Classfile.TAG_NAMEANDTYPE, index, name, type);
|
||||
}
|
||||
|
@ -651,9 +670,31 @@ public abstract sealed class AbstractPoolEntry {
|
|||
return ref2;
|
||||
}
|
||||
|
||||
public ClassDesc fieldTypeSymbol() {
|
||||
if (typeSym instanceof ClassDesc cd) {
|
||||
return cd;
|
||||
} else {
|
||||
return (ClassDesc)(typeSym = ClassDesc.ofDescriptor(ref2.stringValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public MethodTypeDesc methodTypeSymbol() {
|
||||
if (typeSym instanceof MethodTypeDesc mtd) {
|
||||
return mtd;
|
||||
} else {
|
||||
return (MethodTypeDesc)(typeSym = MethodTypeDesc.ofDescriptor(ref2.stringValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NameAndTypeEntry clone(ConstantPoolBuilder cp) {
|
||||
return cp.canWriteDirect(constantPool) ? this : cp.nameAndTypeEntry(ref1, ref2);
|
||||
if (cp.canWriteDirect(constantPool)) {
|
||||
return this;
|
||||
} else {
|
||||
var ret = (NameAndTypeEntryImpl)cp.nameAndTypeEntry(ref1, ref2);
|
||||
ret.typeSym = typeSym;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -918,6 +959,8 @@ public abstract sealed class AbstractPoolEntry {
|
|||
extends AbstractRefEntry<Utf8EntryImpl>
|
||||
implements MethodTypeEntry {
|
||||
|
||||
public MethodTypeDesc sym = null;
|
||||
|
||||
MethodTypeEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl descriptor) {
|
||||
super(cpm, Classfile.TAG_METHODTYPE, index, descriptor);
|
||||
}
|
||||
|
@ -929,7 +972,22 @@ public abstract sealed class AbstractPoolEntry {
|
|||
|
||||
@Override
|
||||
public MethodTypeEntry clone(ConstantPoolBuilder cp) {
|
||||
return cp.canWriteDirect(constantPool) ? this : cp.methodTypeEntry(ref1);
|
||||
if (cp.canWriteDirect(constantPool)) {
|
||||
return this;
|
||||
} else {
|
||||
var ret = (MethodTypeEntryImpl)cp.methodTypeEntry(ref1);
|
||||
ret.sym = sym;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc asSymbol() {
|
||||
var sym = this.sym;
|
||||
if (sym != null) {
|
||||
return sym;
|
||||
}
|
||||
return this.sym = MethodTypeDesc.ofDescriptor(descriptor().stringValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -60,7 +60,7 @@ public final class BufferedCodeBuilder
|
|||
this.endLabel = new LabelImpl(this, -1);
|
||||
this.original = original;
|
||||
this.methodInfo = methodInfo;
|
||||
this.maxLocals = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodType().stringValue());
|
||||
this.maxLocals = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol());
|
||||
if (original != null)
|
||||
this.maxLocals = Math.max(this.maxLocals, original.maxLocals());
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -51,6 +52,7 @@ public final class BufferedMethodBuilder
|
|||
private AccessFlags flags;
|
||||
private final MethodModel original;
|
||||
private int[] parameterSlots;
|
||||
MethodTypeDesc mDesc;
|
||||
|
||||
public BufferedMethodBuilder(SplitConstantPool constantPool,
|
||||
Utf8Entry nameInfo,
|
||||
|
@ -91,6 +93,18 @@ public final class BufferedMethodBuilder
|
|||
return desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc methodTypeSymbol() {
|
||||
if (mDesc == null) {
|
||||
if (original instanceof MethodInfo mi) {
|
||||
mDesc = mi.methodTypeSymbol();
|
||||
} else {
|
||||
mDesc = MethodTypeDesc.ofDescriptor(methodType().stringValue());
|
||||
}
|
||||
}
|
||||
return mDesc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int methodFlags() {
|
||||
return flags.flagsMask();
|
||||
|
@ -99,7 +113,7 @@ public final class BufferedMethodBuilder
|
|||
@Override
|
||||
public int parameterSlot(int paramNo) {
|
||||
if (parameterSlots == null)
|
||||
parameterSlots = Util.parseParameterSlots(methodFlags(), methodType().stringValue());
|
||||
parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol());
|
||||
return parameterSlots[paramNo];
|
||||
}
|
||||
|
||||
|
@ -158,6 +172,11 @@ public final class BufferedMethodBuilder
|
|||
return desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc methodTypeSymbol() {
|
||||
return BufferedMethodBuilder.this.methodTypeSymbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int methodFlags() {
|
||||
return flags.flagsMask();
|
||||
|
|
|
@ -130,7 +130,7 @@ public final class DirectCodeBuilder
|
|||
: new BufWriterImpl(constantPool);
|
||||
this.startLabel = new LabelImpl(this, 0);
|
||||
this.endLabel = new LabelImpl(this, -1);
|
||||
this.topLocal = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodType().stringValue());
|
||||
this.topLocal = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol());
|
||||
if (original != null)
|
||||
this.topLocal = Math.max(this.topLocal, original.maxLocals());
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jdk.internal.classfile.BufWriter;
|
||||
|
@ -46,6 +47,7 @@ public final class DirectMethodBuilder
|
|||
final Utf8Entry desc;
|
||||
int flags;
|
||||
int[] parameterSlots;
|
||||
MethodTypeDesc mDesc;
|
||||
|
||||
public DirectMethodBuilder(SplitConstantPool constantPool,
|
||||
Utf8Entry nameInfo,
|
||||
|
@ -77,6 +79,18 @@ public final class DirectMethodBuilder
|
|||
return desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc methodTypeSymbol() {
|
||||
if (mDesc == null) {
|
||||
if (original instanceof MethodInfo mi) {
|
||||
mDesc = mi.methodTypeSymbol();
|
||||
} else {
|
||||
mDesc = MethodTypeDesc.ofDescriptor(methodType().stringValue());
|
||||
}
|
||||
}
|
||||
return mDesc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int methodFlags() {
|
||||
return flags;
|
||||
|
@ -85,7 +99,7 @@ public final class DirectMethodBuilder
|
|||
@Override
|
||||
public int parameterSlot(int paramNo) {
|
||||
if (parameterSlots == null)
|
||||
parameterSlots = Util.parseParameterSlots(methodFlags(), methodType().stringValue());
|
||||
parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol());
|
||||
return parameterSlots[paramNo];
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import jdk.internal.classfile.*;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
|
||||
|
@ -39,6 +40,7 @@ public final class MethodImpl
|
|||
private final int startPos, endPos, attributesPos;
|
||||
private List<Attribute<?>> attributes;
|
||||
private int[] parameterSlots;
|
||||
private MethodTypeDesc mDesc;
|
||||
|
||||
public MethodImpl(ClassReader reader, int startPos, int endPos, int attrStart) {
|
||||
this.reader = reader;
|
||||
|
@ -70,6 +72,14 @@ public final class MethodImpl
|
|||
return reader.readUtf8Entry(startPos + 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTypeDesc methodTypeSymbol() {
|
||||
if (mDesc == null) {
|
||||
mDesc = MethodTypeDesc.ofDescriptor(methodType().stringValue());
|
||||
}
|
||||
return mDesc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int methodFlags() {
|
||||
return reader.readU2(startPos);
|
||||
|
@ -78,7 +88,7 @@ public final class MethodImpl
|
|||
@Override
|
||||
public int parameterSlot(int paramNo) {
|
||||
if (parameterSlots == null)
|
||||
parameterSlots = Util.parseParameterSlots(methodFlags(), methodType().stringValue());
|
||||
parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol());
|
||||
return parameterSlots[paramNo];
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
|
||||
import static jdk.internal.classfile.Classfile.ACC_STATIC;
|
||||
|
@ -31,6 +32,7 @@ import static jdk.internal.classfile.Classfile.ACC_STATIC;
|
|||
public interface MethodInfo {
|
||||
Utf8Entry methodName();
|
||||
Utf8Entry methodType();
|
||||
MethodTypeDesc methodTypeSymbol();
|
||||
int methodFlags();
|
||||
|
||||
default int receiverSlot() {
|
||||
|
|
|
@ -103,6 +103,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
|
|||
this.parentSize = 0;
|
||||
this.parentBsmSize = 0;
|
||||
this.options = options;
|
||||
this.doneFullScan = true;
|
||||
}
|
||||
|
||||
public SplitConstantPool(ClassReader parent) {
|
||||
|
@ -380,8 +381,9 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
|
|||
|
||||
@Override
|
||||
public AbstractPoolEntry.Utf8EntryImpl utf8Entry(String s) {
|
||||
var ce = tryFindUtf8(AbstractPoolEntry.hashString(s.hashCode()), s);
|
||||
return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, s)) : ce;
|
||||
int hash = AbstractPoolEntry.hashString(s.hashCode());
|
||||
var ce = tryFindUtf8(hash, s);
|
||||
return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, s, hash)) : ce;
|
||||
}
|
||||
|
||||
AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) {
|
||||
|
@ -459,7 +461,9 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
|
|||
|
||||
@Override
|
||||
public MethodTypeEntry methodTypeEntry(MethodTypeDesc descriptor) {
|
||||
return methodTypeEntry(utf8Entry(descriptor.descriptorString()));
|
||||
var ret = (AbstractPoolEntry.MethodTypeEntryImpl)methodTypeEntry(utf8Entry(descriptor.descriptorString()));
|
||||
ret.sym = descriptor;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,7 +44,7 @@ public final class StackCounter {
|
|||
dcb,
|
||||
buf.thisClass().asSymbol(),
|
||||
dcb.methodInfo.methodName().stringValue(),
|
||||
MethodTypeDesc.ofDescriptor(dcb.methodInfo.methodType().stringValue()),
|
||||
dcb.methodInfo.methodTypeSymbol(),
|
||||
(dcb.methodInfo.methodFlags() & ACC_STATIC) != 0,
|
||||
dcb.bytecodesBufWriter.asByteBuffer().slice(0, dcb.bytecodesBufWriter.size()),
|
||||
dcb.constantPool,
|
||||
|
@ -106,7 +106,7 @@ public final class StackCounter {
|
|||
for (var h : handlers) map.put(labelContext.labelToBci(h.handler), 1);
|
||||
maxLocals = isStatic ? 0 : 1;
|
||||
for (var cd : methodDesc.parameterList()) {
|
||||
maxLocals += TypeKind.from(cd).slotSize();
|
||||
maxLocals += Util.slotSize(cd);
|
||||
}
|
||||
bcs = new RawBytecodeHelper(bytecode);
|
||||
visited = new BitSet(bcs.endBci);
|
||||
|
|
|
@ -63,31 +63,30 @@ public class StackMapDecoder {
|
|||
static List<VerificationTypeInfo> initFrameLocals(MethodModel method) {
|
||||
return initFrameLocals(method.parent().orElseThrow().thisClass(),
|
||||
method.methodName().stringValue(),
|
||||
method.methodType().stringValue(),
|
||||
method.methodTypeSymbol(),
|
||||
method.flags().has(AccessFlag.STATIC));
|
||||
}
|
||||
|
||||
public static List<VerificationTypeInfo> initFrameLocals(ClassEntry thisClass, String methodName, String methodType, boolean isStatic) {
|
||||
var mdesc = MethodTypeDesc.ofDescriptor(methodType);
|
||||
public static List<VerificationTypeInfo> initFrameLocals(ClassEntry thisClass, String methodName, MethodTypeDesc methodType, boolean isStatic) {
|
||||
VerificationTypeInfo vtis[];
|
||||
int i = 0;
|
||||
if (!isStatic) {
|
||||
vtis = new VerificationTypeInfo[mdesc.parameterCount() + 1];
|
||||
vtis = new VerificationTypeInfo[methodType.parameterCount() + 1];
|
||||
if ("<init>".equals(methodName) && !ConstantDescs.CD_Object.equals(thisClass.asSymbol())) {
|
||||
vtis[i++] = SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS;
|
||||
} else {
|
||||
vtis[i++] = new StackMapDecoder.ObjectVerificationTypeInfoImpl(thisClass);
|
||||
}
|
||||
} else {
|
||||
vtis = new VerificationTypeInfo[mdesc.parameterCount()];
|
||||
vtis = new VerificationTypeInfo[methodType.parameterCount()];
|
||||
}
|
||||
for(var arg : mdesc.parameterList()) {
|
||||
vtis[i++] = switch (arg.descriptorString()) {
|
||||
case "I", "S", "C" ,"B", "Z" -> SimpleVerificationTypeInfo.ITEM_INTEGER;
|
||||
case "J" -> SimpleVerificationTypeInfo.ITEM_LONG;
|
||||
case "F" -> SimpleVerificationTypeInfo.ITEM_FLOAT;
|
||||
case "D" -> SimpleVerificationTypeInfo.ITEM_DOUBLE;
|
||||
case "V" -> throw new IllegalArgumentException("Illegal method argument type: " + arg);
|
||||
for(var arg : methodType.parameterList()) {
|
||||
vtis[i++] = switch (arg.descriptorString().charAt(0)) {
|
||||
case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.ITEM_INTEGER;
|
||||
case 'J' -> SimpleVerificationTypeInfo.ITEM_LONG;
|
||||
case 'F' -> SimpleVerificationTypeInfo.ITEM_FLOAT;
|
||||
case 'D' -> SimpleVerificationTypeInfo.ITEM_DOUBLE;
|
||||
case 'V' -> throw new IllegalArgumentException("Illegal method argument type: " + arg);
|
||||
default -> new StackMapDecoder.ObjectVerificationTypeInfoImpl(TemporaryConstantPool.INSTANCE.classEntry(arg));
|
||||
};
|
||||
}
|
||||
|
@ -100,7 +99,7 @@ public class StackMapDecoder {
|
|||
var mi = dcb.methodInfo();
|
||||
var prevLocals = StackMapDecoder.initFrameLocals(buf.thisClass(),
|
||||
mi.methodName().stringValue(),
|
||||
mi.methodType().stringValue(),
|
||||
mi.methodTypeSymbol(),
|
||||
(mi.methodFlags() & ACC_STATIC) != 0);
|
||||
int prevOffset = -1;
|
||||
var map = new TreeMap<Integer, StackMapFrameInfo>();
|
||||
|
|
|
@ -149,7 +149,7 @@ public final class StackMapGenerator {
|
|||
dcb,
|
||||
buf.thisClass().asSymbol(),
|
||||
dcb.methodInfo.methodName().stringValue(),
|
||||
MethodTypeDesc.ofDescriptor(dcb.methodInfo.methodType().stringValue()),
|
||||
dcb.methodInfo.methodTypeSymbol(),
|
||||
(dcb.methodInfo.methodFlags() & ACC_STATIC) != 0,
|
||||
dcb.bytecodesBufWriter.asByteBuffer().slice(0, dcb.bytecodesBufWriter.size()),
|
||||
dcb.constantPool,
|
||||
|
@ -181,6 +181,8 @@ public final class StackMapGenerator {
|
|||
Type.BOOLEAN_ARRAY_TYPE, Type.CHAR_ARRAY_TYPE, Type.FLOAT_ARRAY_TYPE, Type.DOUBLE_ARRAY_TYPE,
|
||||
Type.BYTE_ARRAY_TYPE, Type.SHORT_ARRAY_TYPE, Type.INT_ARRAY_TYPE, Type.LONG_ARRAY_TYPE};
|
||||
|
||||
static record RawExceptionCatch(int start, int end, int handler, Type catchType) {}
|
||||
|
||||
private final Type thisType;
|
||||
private final String methodName;
|
||||
private final MethodTypeDesc methodDesc;
|
||||
|
@ -188,7 +190,8 @@ public final class StackMapGenerator {
|
|||
private final SplitConstantPool cp;
|
||||
private final boolean isStatic;
|
||||
private final LabelContext labelContext;
|
||||
private final List<AbstractPseudoInstruction.ExceptionCatchImpl> exceptionTable;
|
||||
private final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers;
|
||||
private final List<RawExceptionCatch> rawHandlers;
|
||||
private final ClassHierarchyImpl classHierarchy;
|
||||
private final boolean patchDeadCode;
|
||||
private List<Frame> frames;
|
||||
|
@ -226,7 +229,8 @@ public final class StackMapGenerator {
|
|||
this.bytecode = bytecode;
|
||||
this.cp = cp;
|
||||
this.labelContext = labelContext;
|
||||
this.exceptionTable = handlers;
|
||||
this.handlers = handlers;
|
||||
this.rawHandlers = new ArrayList<>(handlers.size());
|
||||
this.classHierarchy = new ClassHierarchyImpl(cp.options().classHierarchyResolver);
|
||||
this.patchDeadCode = cp.options().patchCode;
|
||||
this.currentFrame = new Frame(classHierarchy);
|
||||
|
@ -249,19 +253,25 @@ public final class StackMapGenerator {
|
|||
return maxStack;
|
||||
}
|
||||
|
||||
private int getFrameIndexFromOffset(int offset) {
|
||||
int i = 0;
|
||||
for (; i < frames.size(); i++) {
|
||||
if (frames.get(i).offset == offset) {
|
||||
return i;
|
||||
}
|
||||
private Frame getFrame(int offset) {
|
||||
//binary search over frames ordered by offset
|
||||
int low = 0;
|
||||
int high = frames.size() - 1;
|
||||
while (low <= high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
var f = frames.get(mid);
|
||||
if (f.offset < offset)
|
||||
low = mid + 1;
|
||||
else if (f.offset > offset)
|
||||
high = mid - 1;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
return i;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkJumpTarget(Frame frame, int target) {
|
||||
int index = getFrameIndexFromOffset(target);
|
||||
frame.checkAssignableTo(frames.get(index));
|
||||
frame.checkAssignableTo(getFrame(target));
|
||||
}
|
||||
|
||||
private int exMin, exMax;
|
||||
|
@ -276,11 +286,18 @@ public final class StackMapGenerator {
|
|||
private void generate() {
|
||||
exMin = bytecode.capacity();
|
||||
exMax = -1;
|
||||
for (var exhandler : exceptionTable) {
|
||||
for (var exhandler : handlers) {
|
||||
int start_pc = labelContext.labelToBci(exhandler.tryStart());
|
||||
int end_pc = labelContext.labelToBci(exhandler.tryEnd());
|
||||
if (start_pc < exMin) exMin = start_pc;
|
||||
if (end_pc > exMax) exMax = end_pc;
|
||||
int handler_pc = labelContext.labelToBci(exhandler.handler());
|
||||
if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) {
|
||||
if (start_pc < exMin) exMin = start_pc;
|
||||
if (end_pc > exMax) exMax = end_pc;
|
||||
var catchType = exhandler.catchType();
|
||||
rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc,
|
||||
catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp)
|
||||
: Type.THROWABLE_TYPE));
|
||||
}
|
||||
}
|
||||
BitSet frameOffsets = detectFrameOffsets();
|
||||
int framesCount = frameOffsets.cardinality();
|
||||
|
@ -318,7 +335,7 @@ public final class StackMapGenerator {
|
|||
}
|
||||
|
||||
private void removeRangeFromExcTable(int rangeStart, int rangeEnd) {
|
||||
var it = exceptionTable.listIterator();
|
||||
var it = handlers.listIterator();
|
||||
while (it.hasNext()) {
|
||||
var e = it.next();
|
||||
int handlerStart = labelContext.labelToBci(e.tryStart());
|
||||
|
@ -379,10 +396,6 @@ public final class StackMapGenerator {
|
|||
return Type.referenceType(((ClassEntry)cp.entryByIndex(index)).asSymbol());
|
||||
}
|
||||
|
||||
private static boolean isDoubleSlot(ClassDesc desc) {
|
||||
return CD_double.equals(desc) || CD_long.equals(desc);
|
||||
}
|
||||
|
||||
private void processMethod() {
|
||||
currentFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType);
|
||||
currentFrame.stackSize = 0;
|
||||
|
@ -651,17 +664,15 @@ public final class StackMapGenerator {
|
|||
}
|
||||
|
||||
private void processExceptionHandlerTargets(int bci, boolean this_uninit) {
|
||||
for (var exhandler : exceptionTable) {
|
||||
if (bci >= labelContext.labelToBci(exhandler.tryStart()) && bci < labelContext.labelToBci(exhandler.tryEnd())) {
|
||||
for (var ex : rawHandlers) {
|
||||
if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) {
|
||||
int flags = currentFrame.flags;
|
||||
if (this_uninit) flags |= FLAG_THIS_UNINIT;
|
||||
Frame newFrame = currentFrame.frameInExceptionHandler(flags);
|
||||
var catchType = exhandler.catchType();
|
||||
newFrame.pushStack(catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp) : Type.THROWABLE_TYPE);
|
||||
int handler = labelContext.labelToBci(exhandler.handler());
|
||||
if (handler != -1) checkJumpTarget(newFrame, handler);
|
||||
Frame newFrame = currentFrame.frameInExceptionHandler(flags, ex.catchType);
|
||||
checkJumpTarget(newFrame, ex.handler);
|
||||
}
|
||||
}
|
||||
currentFrame.localsChanged = false;
|
||||
}
|
||||
|
||||
private void processLdc(int index) {
|
||||
|
@ -732,13 +743,13 @@ public final class StackMapGenerator {
|
|||
}
|
||||
|
||||
private void processFieldInstructions(RawBytecodeHelper bcs) {
|
||||
var desc = ClassDesc.ofDescriptor(((MemberRefEntry)cp.entryByIndex(bcs.getIndexU2())).nameAndType().type().stringValue());
|
||||
var desc = Util.fieldTypeSymbol(((MemberRefEntry)cp.entryByIndex(bcs.getIndexU2())).nameAndType());
|
||||
switch (bcs.rawCode) {
|
||||
case GETSTATIC ->
|
||||
currentFrame.pushStack(desc);
|
||||
case PUTSTATIC -> {
|
||||
currentFrame.popStack();
|
||||
if (isDoubleSlot(desc)) currentFrame.popStack();
|
||||
if (Util.isDoubleSlot(desc)) currentFrame.popStack();
|
||||
}
|
||||
case GETFIELD -> {
|
||||
currentFrame.popStack();
|
||||
|
@ -747,7 +758,7 @@ public final class StackMapGenerator {
|
|||
case PUTFIELD -> {
|
||||
currentFrame.popStack();
|
||||
currentFrame.popStack();
|
||||
if (isDoubleSlot(desc)) currentFrame.popStack();
|
||||
if (Util.isDoubleSlot(desc)) currentFrame.popStack();
|
||||
}
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
|
@ -759,36 +770,9 @@ public final class StackMapGenerator {
|
|||
var cpe = cp.entryByIndex(index);
|
||||
var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType();
|
||||
String invokeMethodName = nameAndType.name().stringValue();
|
||||
|
||||
var mDesc = nameAndType.type().stringValue();
|
||||
//faster counting of method descriptor argument slots instead of full parsing
|
||||
int nargs = 0, pos = 0, descLen = mDesc.length();
|
||||
if (descLen < 3 || mDesc.charAt(0) != '(')
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + mDesc);
|
||||
char ch;
|
||||
while (++pos < descLen && (ch = mDesc.charAt(pos)) != ')') {
|
||||
switch (ch) {
|
||||
case '[' -> {
|
||||
nargs++;
|
||||
while (++pos < descLen && mDesc.charAt(pos) == '[');
|
||||
if (mDesc.charAt(pos) == 'L')
|
||||
while (++pos < descLen && mDesc.charAt(pos) != ';');
|
||||
}
|
||||
case 'D', 'J' -> nargs += 2;
|
||||
case 'B', 'C', 'F', 'I', 'S', 'Z' -> nargs++;
|
||||
case 'L' -> {
|
||||
nargs++;
|
||||
while (++pos < descLen && mDesc.charAt(pos) != ';');
|
||||
}
|
||||
default ->
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + mDesc);
|
||||
}
|
||||
}
|
||||
if (++pos >= descLen)
|
||||
throw new IllegalArgumentException("Bad method descriptor: " + mDesc);
|
||||
|
||||
var mDesc = Util.methodTypeSymbol(nameAndType);
|
||||
int bci = bcs.bci;
|
||||
currentFrame.decStack(nargs);
|
||||
currentFrame.decStack(Util.parameterSlots(mDesc));
|
||||
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
|
||||
if (OBJECT_INITIALIZER_NAME.equals(invokeMethodName)) {
|
||||
Type type = currentFrame.popStack();
|
||||
|
@ -813,7 +797,7 @@ public final class StackMapGenerator {
|
|||
currentFrame.popStack();
|
||||
}
|
||||
}
|
||||
currentFrame.pushStack(ClassDesc.ofDescriptor(mDesc.substring(pos)));
|
||||
currentFrame.pushStack(mDesc.returnType());
|
||||
return thisUninit;
|
||||
}
|
||||
|
||||
|
@ -944,8 +928,8 @@ public final class StackMapGenerator {
|
|||
} catch (IllegalArgumentException iae) {
|
||||
generatorError("Detected branch target out of bytecode range", bci);
|
||||
}
|
||||
for (var exhandler : exceptionTable) try {
|
||||
offsets.set(labelContext.labelToBci(exhandler.handler()));
|
||||
for (var exhandler : rawHandlers) try {
|
||||
offsets.set(exhandler.handler());
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if (!cp.options().filterDeadLabels)
|
||||
generatorError("Detected exception handler out of bytecode range");
|
||||
|
@ -960,6 +944,7 @@ public final class StackMapGenerator {
|
|||
int flags;
|
||||
int frameMaxStack = 0, frameMaxLocals = 0;
|
||||
boolean dirty = false;
|
||||
boolean localsChanged = false;
|
||||
|
||||
private final ClassHierarchyImpl classHierarchy;
|
||||
|
||||
|
@ -989,16 +974,16 @@ public final class StackMapGenerator {
|
|||
}
|
||||
|
||||
Frame pushStack(ClassDesc desc) {
|
||||
return switch (desc.descriptorString()) {
|
||||
case "J" ->
|
||||
return switch (desc.descriptorString().charAt(0)) {
|
||||
case 'J' ->
|
||||
pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
case "D" ->
|
||||
case 'D' ->
|
||||
pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case "I", "Z", "B", "C", "S" ->
|
||||
case 'I', 'Z', 'B', 'C', 'S' ->
|
||||
pushStack(Type.INTEGER_TYPE);
|
||||
case "F" ->
|
||||
case 'F' ->
|
||||
pushStack(Type.FLOAT_TYPE);
|
||||
case "V" ->
|
||||
case 'V' ->
|
||||
this;
|
||||
default ->
|
||||
pushStack(Type.referenceType(desc));
|
||||
|
@ -1029,8 +1014,8 @@ public final class StackMapGenerator {
|
|||
return this;
|
||||
}
|
||||
|
||||
Frame frameInExceptionHandler(int flags) {
|
||||
return new Frame(offset, flags, localsSize, 0, locals, new Type[] {Type.TOP_TYPE}, classHierarchy);
|
||||
Frame frameInExceptionHandler(int flags, Type excType) {
|
||||
return new Frame(offset, flags, localsSize, 1, locals, new Type[] {excType}, classHierarchy);
|
||||
}
|
||||
|
||||
void initializeObject(Type old_object, Type new_object) {
|
||||
|
@ -1038,6 +1023,7 @@ public final class StackMapGenerator {
|
|||
for (i = 0; i < localsSize; i++) {
|
||||
if (locals[i].equals(old_object)) {
|
||||
locals[i] = new_object;
|
||||
localsChanged = true;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < stackSize; i++) {
|
||||
|
@ -1077,6 +1063,7 @@ public final class StackMapGenerator {
|
|||
|
||||
private void setLocalRawInternal(int index, Type type) {
|
||||
checkLocal(index);
|
||||
localsChanged |= !type.equals(locals[index]);
|
||||
locals[index] = type;
|
||||
}
|
||||
|
||||
|
@ -1095,18 +1082,18 @@ public final class StackMapGenerator {
|
|||
var desc = methodDesc.parameterType(i);
|
||||
if (desc.isClassOrInterface() || desc.isArray()) {
|
||||
setLocalRawInternal(localsSize++, Type.referenceType(desc));
|
||||
} else switch (desc.descriptorString()) {
|
||||
case "J" -> {
|
||||
} else switch (desc.descriptorString().charAt(0)) {
|
||||
case 'J' -> {
|
||||
setLocalRawInternal(localsSize++, Type.LONG_TYPE);
|
||||
setLocalRawInternal(localsSize++, Type.LONG2_TYPE);
|
||||
}
|
||||
case "D" -> {
|
||||
case 'D' -> {
|
||||
setLocalRawInternal(localsSize++, Type.DOUBLE_TYPE);
|
||||
setLocalRawInternal(localsSize++, Type.DOUBLE2_TYPE);
|
||||
}
|
||||
case "I", "Z", "B", "C", "S" ->
|
||||
case 'I', 'Z', 'B', 'C', 'S' ->
|
||||
setLocalRawInternal(localsSize++, Type.INTEGER_TYPE);
|
||||
case "F" ->
|
||||
case 'F' ->
|
||||
setLocalRawInternal(localsSize++, Type.FLOAT_TYPE);
|
||||
default -> throw new AssertionError("Should not reach here");
|
||||
}
|
||||
|
@ -1123,6 +1110,7 @@ public final class StackMapGenerator {
|
|||
checkStack(src.stackSize - 1);
|
||||
if (src.stackSize > 0) System.arraycopy(src.stack, 0, stack, 0, src.stackSize);
|
||||
flags = src.flags;
|
||||
localsChanged = true;
|
||||
}
|
||||
|
||||
void checkAssignableTo(Frame target) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.AbstractList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
|
@ -35,6 +36,7 @@ import java.util.function.Function;
|
|||
import jdk.internal.classfile.Opcode;
|
||||
import jdk.internal.classfile.constantpool.ClassEntry;
|
||||
import jdk.internal.classfile.constantpool.ModuleEntry;
|
||||
import jdk.internal.classfile.constantpool.NameAndTypeEntry;
|
||||
import java.lang.constant.ModuleDesc;
|
||||
import jdk.internal.classfile.impl.TemporaryConstantPool;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
|
@ -56,61 +58,29 @@ public class Util {
|
|||
return "[" + s;
|
||||
}
|
||||
|
||||
public static BitSet findParams(String type) {
|
||||
BitSet bs = new BitSet();
|
||||
if (type.charAt(0) != '(')
|
||||
throw new IllegalArgumentException();
|
||||
loop: for (int i = 1; i < type.length(); ++i) {
|
||||
switch (type.charAt(i)) {
|
||||
case '[':
|
||||
bs.set(i);
|
||||
while (type.charAt(++i) == '[')
|
||||
;
|
||||
if (type.charAt(i) == 'L') {
|
||||
while (type.charAt(++i) != ';')
|
||||
;
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
break loop;
|
||||
default:
|
||||
bs.set(i);
|
||||
if (type.charAt(i) == 'L') {
|
||||
while (type.charAt(++i) != ';')
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
public static int parameterSlots(String type) {
|
||||
BitSet bs = findParams(type);
|
||||
public static int parameterSlots(MethodTypeDesc mDesc) {
|
||||
int count = 0;
|
||||
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
|
||||
count += (type.charAt(i) == 'J' || type.charAt(i) == 'D') ? 2 : 1;
|
||||
for (int i = 0; i < mDesc.parameterCount(); i++) {
|
||||
count += slotSize(mDesc.parameterType(i));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static int[] parseParameterSlots(int flags, String type) {
|
||||
BitSet bs = findParams(type);
|
||||
int[] result = new int[bs.cardinality()];
|
||||
int index = 0;
|
||||
public static int[] parseParameterSlots(int flags, MethodTypeDesc mDesc) {
|
||||
int[] result = new int[mDesc.parameterCount()];
|
||||
int count = ((flags & ACC_STATIC) != 0) ? 0 : 1;
|
||||
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
|
||||
result[index++] = count;
|
||||
count += (type.charAt(i) == 'J' || type.charAt(i) == 'D') ? 2 : 1;
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = count;
|
||||
count += slotSize(mDesc.parameterType(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int maxLocals(int flags, String type) {
|
||||
BitSet bs = findParams(type);
|
||||
public static int maxLocals(int flags, MethodTypeDesc mDesc) {
|
||||
int count = ((flags & ACC_STATIC) != 0) ? 0 : 1;
|
||||
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1))
|
||||
count += (type.charAt(i) == 'J' || type.charAt(i) == 'D') ? 2 : 1;
|
||||
for (int i = 0; i < mDesc.parameterCount(); i++) {
|
||||
count += slotSize(mDesc.parameterType(i));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -187,7 +157,7 @@ public class Util {
|
|||
public static List<ClassEntry> entryList(List<? extends ClassDesc> list) {
|
||||
var result = new Object[list.size()]; // null check
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = TemporaryConstantPool.INSTANCE.classEntry(TemporaryConstantPool.INSTANCE.utf8Entry(toInternalName(list.get(i))));
|
||||
result[i] = TemporaryConstantPool.INSTANCE.classEntry(list.get(i));
|
||||
}
|
||||
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(result);
|
||||
}
|
||||
|
@ -231,4 +201,25 @@ public class Util {
|
|||
public static boolean has(AccessFlag.Location location, int flagsMask, AccessFlag flag) {
|
||||
return (flag.mask() & flagsMask) == flag.mask() && flag.locations().contains(location);
|
||||
}
|
||||
|
||||
public static ClassDesc fieldTypeSymbol(NameAndTypeEntry nat) {
|
||||
return ((AbstractPoolEntry.NameAndTypeEntryImpl)nat).fieldTypeSymbol();
|
||||
}
|
||||
|
||||
public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) {
|
||||
return ((AbstractPoolEntry.NameAndTypeEntryImpl)nat).methodTypeSymbol();
|
||||
}
|
||||
|
||||
public static int slotSize(ClassDesc desc) {
|
||||
return switch (desc.descriptorString().charAt(0)) {
|
||||
case 'V' -> 0;
|
||||
case 'D','J' -> 2;
|
||||
default -> 1;
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isDoubleSlot(ClassDesc desc) {
|
||||
char ch = desc.descriptorString().charAt(0);
|
||||
return ch == 'D' || ch == 'J';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import jdk.internal.classfile.constantpool.FieldRefEntry;
|
|||
import jdk.internal.classfile.constantpool.NameAndTypeEntry;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
import jdk.internal.classfile.impl.AbstractInstruction;
|
||||
import jdk.internal.classfile.impl.AbstractPoolEntry;
|
||||
import jdk.internal.classfile.impl.TemporaryConstantPool;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
||||
|
@ -76,7 +77,7 @@ public sealed interface FieldInstruction extends Instruction
|
|||
* {@return a symbolic descriptor for the type of the field}
|
||||
*/
|
||||
default ClassDesc typeSymbol() {
|
||||
return ClassDesc.ofDescriptor(type().stringValue());
|
||||
return Util.fieldTypeSymbol(field().nameAndType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,6 +37,7 @@ import jdk.internal.classfile.constantpool.InvokeDynamicEntry;
|
|||
import jdk.internal.classfile.constantpool.LoadableConstantEntry;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
import jdk.internal.classfile.impl.AbstractInstruction;
|
||||
import jdk.internal.classfile.impl.AbstractPoolEntry;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
||||
/**
|
||||
|
@ -69,7 +70,7 @@ public sealed interface InvokeDynamicInstruction extends Instruction
|
|||
* {@return the invocation type of the call site, as a symbolic descriptor}
|
||||
*/
|
||||
default MethodTypeDesc typeSymbol() {
|
||||
return MethodTypeDesc.ofDescriptor(type().stringValue());
|
||||
return Util.methodTypeSymbol(invokedynamic().nameAndType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,6 +37,7 @@ import jdk.internal.classfile.constantpool.MethodRefEntry;
|
|||
import jdk.internal.classfile.constantpool.NameAndTypeEntry;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
import jdk.internal.classfile.impl.AbstractInstruction;
|
||||
import jdk.internal.classfile.impl.AbstractPoolEntry;
|
||||
import jdk.internal.classfile.impl.TemporaryConstantPool;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
|
||||
|
@ -89,7 +90,7 @@ public sealed interface InvokeInstruction extends Instruction
|
|||
* {@return a symbolic descriptor for the method type}
|
||||
*/
|
||||
default MethodTypeDesc typeSymbol() {
|
||||
return MethodTypeDesc.ofDescriptor(type().stringValue());
|
||||
return Util.methodTypeSymbol(method().nameAndType());
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue