8323183: ClassFile API performance improvements

Reviewed-by: redestad
This commit is contained in:
Adam Sotona 2024-03-04 15:26:27 +00:00
parent b69d1b51c7
commit 0583f73574
4 changed files with 59 additions and 51 deletions

View file

@ -87,6 +87,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
this.bsmSize = parentBsmSize;
this.myEntries = new PoolEntry[8];
this.myBsmEntries = new BootstrapMethodEntryImpl[8];
this.doneFullScan = true;
}
@Override
@ -189,10 +190,15 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
// 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<parentSize; i++) {
for (int i=1; i<parentSize;) {
PoolEntry cpi = parent.cp[i];
if (cpi != null)
if (cpi == null) {
doneFullScan = false;
i++;
} else {
map.put(cpi.hashCode(), cpi.index());
i += cpi.width();
}
}
for (int i = Math.max(parentSize, 1); i < size; ) {
PoolEntry cpi = myEntries[i - parentSize];

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@ -25,26 +25,26 @@
*/
package jdk.internal.classfile.impl;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.nio.ByteBuffer;
import java.util.BitSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.lang.classfile.TypeKind;
import java.lang.classfile.constantpool.ConstantDynamicEntry;
import java.lang.classfile.constantpool.DynamicConstantPoolEntry;
import java.lang.classfile.constantpool.MemberRefEntry;
import java.lang.constant.MethodTypeDesc;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.BitSet;
import java.util.List;
import java.util.Queue;
import static java.lang.classfile.ClassFile.*;
public final class StackCounter {
private record Target(int bci, int stack) {}
static StackCounter of(DirectCodeBuilder dcb, BufWriterImpl buf) {
return new StackCounter(
dcb,
buf.thisClass().asSymbol(),
dcb.methodInfo.methodName().stringValue(),
dcb.methodInfo.methodTypeSymbol(),
(dcb.methodInfo.methodFlags() & ACC_STATIC) != 0,
@ -59,12 +59,12 @@ public final class StackCounter {
private final String methodName;
private final MethodTypeDesc methodDesc;
private final SplitConstantPool cp;
private final LinkedHashMap<Integer, Integer> map;
private final Queue<Target> targets;
private final BitSet visited;
private void jump(int targetBci) {
if (!visited.get(targetBci)) {
map.put(targetBci, stack);
targets.add(new Target(targetBci, stack));
}
}
@ -78,13 +78,11 @@ public final class StackCounter {
}
private boolean next() {
var it = map.entrySet().iterator();
while (it.hasNext()) {
var en = it.next();
it.remove();
if (!visited.get(en.getKey())) {
bcs.nextBci = en.getKey();
stack = en.getValue();
Target en;
while ((en = targets.poll()) != null) {
if (!visited.get(en.bci)) {
bcs.nextBci = en.bci;
stack = en.stack;
return true;
}
}
@ -93,7 +91,6 @@ public final class StackCounter {
}
public StackCounter(LabelContext labelContext,
ClassDesc thisClass,
String methodName,
MethodTypeDesc methodDesc,
boolean isStatic,
@ -103,16 +100,14 @@ public final class StackCounter {
this.methodName = methodName;
this.methodDesc = methodDesc;
this.cp = cp;
map = new LinkedHashMap<>();
targets = new ArrayDeque<>();
maxStack = stack = rets = 0;
for (var h : handlers) map.put(labelContext.labelToBci(h.handler), 1);
for (var h : handlers) targets.add(new Target(labelContext.labelToBci(h.handler), 1));
maxLocals = isStatic ? 0 : 1;
for (var cd : methodDesc.parameterList()) {
maxLocals += Util.slotSize(cd);
}
maxLocals += Util.parameterSlots(methodDesc);
bcs = new RawBytecodeHelper(bytecode);
visited = new BitSet(bcs.endBci);
map.put(0, 0);
targets.add(new Target(0, 0));
while (next()) {
while (!bcs.isLastBytecode()) {
bcs.rawNext();
@ -307,14 +302,11 @@ public final class StackCounter {
case INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC -> {
var cpe = cp.entryByIndex(bcs.getIndexU2());
var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType();
var mDesc = MethodTypeDesc.ofDescriptor(nameAndType.type().stringValue());
for (var arg : mDesc.parameterList()) {
addStackSlot(-TypeKind.from(arg).slotSize());
}
var mtd = Util.methodTypeSymbol(nameAndType);
addStackSlot(Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd));
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
addStackSlot(-1);
}
addStackSlot(TypeKind.from(mDesc.returnType()).slotSize());
}
case MULTIANEWARRAY ->
addStackSlot (1 - bcs.getU1(bcs.bci + 3));

View file

@ -80,7 +80,8 @@ public class StackMapDecoder {
} else {
vtis = new VerificationTypeInfo[methodType.parameterCount()];
}
for(var arg : methodType.parameterList()) {
for (int pi = 0; pi < methodType.parameterCount(); pi++) {
var arg = methodType.parameterType(pi);
vtis[i++] = switch (arg.descriptorString().charAt(0)) {
case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.ITEM_INTEGER;
case 'J' -> SimpleVerificationTypeInfo.ITEM_LONG;