diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index eb5aab90bb0..db2b4f030a3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -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 map; + private final Queue 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)); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index 0fdb3622d6b..75e9f7d817b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -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; diff --git a/test/micro/org/openjdk/bench/jdk/classfile/GenerateStackMaps.java b/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java similarity index 81% rename from test/micro/org/openjdk/bench/jdk/classfile/GenerateStackMaps.java rename to test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java index 6fcf801c2cf..1a9d989c546 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/GenerateStackMaps.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,7 +24,6 @@ package org.openjdk.bench.jdk.classfile; import java.io.IOException; import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; import java.net.URI; import java.nio.ByteBuffer; import java.nio.file.FileSystems; @@ -34,12 +33,16 @@ import java.util.ArrayList; import java.util.List; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassReader; +import java.lang.classfile.MethodModel; +import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.constant.MethodTypeDesc; import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.classfile.impl.CodeImpl; import jdk.internal.classfile.impl.LabelContext; import jdk.internal.classfile.impl.ClassFileImpl; import jdk.internal.classfile.impl.SplitConstantPool; +import jdk.internal.classfile.impl.StackCounter; import jdk.internal.classfile.impl.StackMapGenerator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -51,6 +54,7 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; @BenchmarkMode(Mode.Throughput) @State(Scope.Benchmark) @@ -58,8 +62,8 @@ import org.openjdk.jmh.annotations.Warmup; "--enable-preview", "--add-exports", "java.base/jdk.internal.classfile.impl=ALL-UNNAMED"}) @Warmup(iterations = 2) -@Measurement(iterations = 10) -public class GenerateStackMaps { +@Measurement(iterations = 8) +public class CodeAttributeTools { record GenData(LabelContext labelContext, ClassDesc thisClass, @@ -71,17 +75,13 @@ public class GenerateStackMaps { List handlers) {} List data; - Iterator it; - GenData d; - ClassFile cc; - @Setup(Level.Trial) + @Setup(Level.Invocation) public void setup() throws IOException { - cc = ClassFile.of(); data = new ArrayList<>(); Files.walk(FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules/java.base/java")).forEach(p -> { if (Files.isRegularFile(p) && p.toString().endsWith(".class")) try { - var clm = cc.parse(p); + var clm = ClassFile.of().parse(p); var thisCls = clm.thisClass().asSymbol(); var cp = new SplitConstantPool((ClassReader)clm.constantPool()); for (var m : clm.methods()) { @@ -105,11 +105,8 @@ public class GenerateStackMaps { } @Benchmark - public void benchmark() { - if (it == null || !it.hasNext()) - it = data.iterator(); - var d = it.next(); - new StackMapGenerator( + public void benchmarkStackMapsGenerator(Blackhole bh) { + for (var d : data) bh.consume(new StackMapGenerator( d.labelContext(), d.thisClass(), d.methodName(), @@ -117,7 +114,19 @@ public class GenerateStackMaps { d.isStatic(), d.bytecode().rewind(), (SplitConstantPool)d.constantPool(), - (ClassFileImpl)cc, - d.handlers()); + (ClassFileImpl)ClassFile.of(), + d.handlers())); + } + + @Benchmark + public void benchmarkStackCounter(Blackhole bh) { + for (var d : data) bh.consume(new StackCounter( + d.labelContext(), + d.methodName(), + d.methodDesc(), + d.isStatic(), + d.bytecode().rewind(), + (SplitConstantPool)d.constantPool(), + d.handlers())); } }