mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-03 10:20:57 +00:00
8354899: Reduce overhead associated with type switches
Reviewed-by: asotona
This commit is contained in:
parent
ffe6a4f9e1
commit
bd1c53e960
@ -27,6 +27,8 @@ package java.lang.runtime;
|
||||
|
||||
import java.lang.Enum.EnumDesc;
|
||||
import java.lang.classfile.CodeBuilder;
|
||||
import java.lang.classfile.attribute.StackMapFrameInfo;
|
||||
import java.lang.classfile.attribute.StackMapTableAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
@ -48,6 +50,7 @@ import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.Label;
|
||||
import java.lang.classfile.instruction.SwitchCase;
|
||||
|
||||
import jdk.internal.classfile.impl.DirectCodeBuilder;
|
||||
import jdk.internal.constant.ClassOrInterfaceDescImpl;
|
||||
import jdk.internal.constant.ConstantUtils;
|
||||
import jdk.internal.constant.MethodTypeDescImpl;
|
||||
@ -103,6 +106,13 @@ public final class SwitchBootstraps {
|
||||
private static final MethodType MT_TYPE_SWITCH = MethodType.methodType(int.class,
|
||||
Object.class,
|
||||
int.class);
|
||||
private static final List<StackMapFrameInfo.VerificationTypeInfo> TYPE_SWITCH_LOCALS = List.of(
|
||||
StackMapFrameInfo.ObjectVerificationTypeInfo.of(CD_Object), StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER
|
||||
);
|
||||
private static final List<StackMapFrameInfo.VerificationTypeInfo> TYPE_SWITCH_EXTRA_LOCALS = List.of(
|
||||
StackMapFrameInfo.ObjectVerificationTypeInfo.of(CD_Object), StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER,
|
||||
StackMapFrameInfo.ObjectVerificationTypeInfo.of(CD_BiPredicate), StackMapFrameInfo.ObjectVerificationTypeInfo.of(CD_List)
|
||||
);
|
||||
|
||||
private static class StaticHolders {
|
||||
private static final MethodHandle MAPPED_ENUM_SWITCH;
|
||||
@ -482,8 +492,11 @@ public final class SwitchBootstraps {
|
||||
int ENUM_CACHE = 2;
|
||||
int EXTRA_CLASS_LABELS = 3;
|
||||
|
||||
var locals = enumDescs == null && extraClassLabels == null ? TYPE_SWITCH_LOCALS : TYPE_SWITCH_EXTRA_LOCALS;
|
||||
|
||||
return cb -> {
|
||||
// Objects.checkIndex(RESTART_IDX, labelConstants + 1)
|
||||
var stackMapFrames = new ArrayList<StackMapFrameInfo>(labelConstants.length * 2);
|
||||
cb.iload(RESTART_IDX)
|
||||
.loadConstant(labelConstants.length + 1)
|
||||
.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR)
|
||||
@ -494,9 +507,12 @@ public final class SwitchBootstraps {
|
||||
.iconst_m1()
|
||||
.ireturn()
|
||||
.labelBinding(nonNullLabel);
|
||||
stackMapFrames.add(StackMapFrameInfo.of(nonNullLabel, locals, List.of()));
|
||||
if (labelConstants.length == 0) {
|
||||
cb.loadConstant(0)
|
||||
.ireturn();
|
||||
.ireturn()
|
||||
.with(StackMapTableAttribute.of(stackMapFrames));
|
||||
DirectCodeBuilder.withMaxs(cb, 2, locals.size()); // checkIndex uses 2
|
||||
return;
|
||||
}
|
||||
cb.iload(RESTART_IDX);
|
||||
@ -509,6 +525,7 @@ public final class SwitchBootstraps {
|
||||
for (int idx = labelConstants.length - 1; idx >= 0; idx--) {
|
||||
Object currentLabel = labelConstants[idx];
|
||||
Label target = cb.newLabel();
|
||||
stackMapFrames.add(StackMapFrameInfo.of(target, locals, List.of()));
|
||||
Label next;
|
||||
if (lastLabel == null) {
|
||||
next = dflt;
|
||||
@ -541,7 +558,7 @@ public final class SwitchBootstraps {
|
||||
} else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) {
|
||||
// Integer i = ... or int i = ...
|
||||
// o instanceof float
|
||||
Label notNumber = cb.newLabel();
|
||||
Label notNumber = cb.newLabel(); // this label may end up unbound
|
||||
cb.aload(SELECTOR_OBJ)
|
||||
.instanceOf(CD_Number);
|
||||
if (selectorType == long.class || selectorType == float.class || selectorType == double.class ||
|
||||
@ -570,8 +587,9 @@ public final class SwitchBootstraps {
|
||||
"intValue",
|
||||
MethodTypeDesc.of(CD_int))
|
||||
.goto_(compare)
|
||||
.labelBinding(notNumber)
|
||||
.aload(SELECTOR_OBJ)
|
||||
.labelBinding(notNumber);
|
||||
stackMapFrames.add(StackMapFrameInfo.of(notNumber, locals, List.of()));
|
||||
cb.aload(SELECTOR_OBJ)
|
||||
.instanceOf(CD_Character)
|
||||
.ifeq(next)
|
||||
.aload(SELECTOR_OBJ)
|
||||
@ -580,6 +598,7 @@ public final class SwitchBootstraps {
|
||||
"charValue",
|
||||
MethodTypeDesc.of(CD_char))
|
||||
.labelBinding(compare);
|
||||
stackMapFrames.add(StackMapFrameInfo.of(compare, locals, List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER)));
|
||||
}
|
||||
|
||||
TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel);
|
||||
@ -648,8 +667,9 @@ public final class SwitchBootstraps {
|
||||
"intValue",
|
||||
MethodTypeDesc.of(CD_int))
|
||||
.goto_(compare)
|
||||
.labelBinding(notNumber)
|
||||
.aload(SELECTOR_OBJ)
|
||||
.labelBinding(notNumber);
|
||||
stackMapFrames.add(StackMapFrameInfo.of(notNumber, locals, List.of()));
|
||||
cb.aload(SELECTOR_OBJ)
|
||||
.instanceOf(CD_Character)
|
||||
.ifeq(next)
|
||||
.aload(SELECTOR_OBJ)
|
||||
@ -657,9 +677,9 @@ public final class SwitchBootstraps {
|
||||
.invokevirtual(CD_Character,
|
||||
"charValue",
|
||||
MethodTypeDesc.of(CD_char))
|
||||
.labelBinding(compare)
|
||||
|
||||
.loadConstant(integerLabel)
|
||||
.labelBinding(compare);
|
||||
stackMapFrames.add(StackMapFrameInfo.of(compare, locals, List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER)));
|
||||
cb.loadConstant(integerLabel)
|
||||
.if_icmpne(next);
|
||||
} else if ((caseLabel instanceof Long ||
|
||||
caseLabel instanceof Float ||
|
||||
@ -688,9 +708,12 @@ public final class SwitchBootstraps {
|
||||
cb.loadConstant(idx)
|
||||
.ireturn();
|
||||
}
|
||||
stackMapFrames.add(StackMapFrameInfo.of(dflt, locals, List.of()));
|
||||
cb.labelBinding(dflt)
|
||||
.loadConstant(labelConstants.length)
|
||||
.ireturn();
|
||||
.ireturn()
|
||||
.with(StackMapTableAttribute.of(stackMapFrames));
|
||||
DirectCodeBuilder.withMaxs(cb, 3, locals.size()); // enum labels use 3 stack, others use 2
|
||||
};
|
||||
}
|
||||
|
||||
@ -702,7 +725,7 @@ public final class SwitchBootstraps {
|
||||
List<EnumDesc<?>> enumDescs = addExtraInfo ? new ArrayList<>() : null;
|
||||
List<Class<?>> extraClassLabels = addExtraInfo ? new ArrayList<>() : null;
|
||||
|
||||
byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())),
|
||||
byte[] classBytes = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS).build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())),
|
||||
clb -> {
|
||||
clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC)
|
||||
.withMethodBody("typeSwitch",
|
||||
|
||||
@ -48,10 +48,8 @@ public final class DirectCodeBuilder
|
||||
extends AbstractDirectBuilder<CodeModel>
|
||||
implements TerminalCodeBuilder {
|
||||
private static final CharacterRange[] EMPTY_CHARACTER_RANGE = {};
|
||||
private static final DeferredLabel[] EMPTY_LABEL_ARRAY = {};
|
||||
private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {};
|
||||
private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {};
|
||||
private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {};
|
||||
private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {};
|
||||
|
||||
final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers = new ArrayList<>();
|
||||
@ -74,6 +72,9 @@ public final class DirectCodeBuilder
|
||||
private DeferredLabel[] deferredLabels = EMPTY_DEFERRED_LABEL_ARRAY;
|
||||
private int deferredLabelsCount = 0;
|
||||
|
||||
private int maxStackHint = -1;
|
||||
private int maxLocalsHint = -1;
|
||||
|
||||
/* Locals management
|
||||
lazily computed maxLocal = -1
|
||||
first time: derive count from methodType descriptor (for new methods) & ACC_STATIC,
|
||||
@ -173,6 +174,12 @@ public final class DirectCodeBuilder
|
||||
return methodInfo;
|
||||
}
|
||||
|
||||
public static void withMaxs(CodeBuilder cob, int stacks, int locals) {
|
||||
var dcb = (DirectCodeBuilder) cob;
|
||||
dcb.maxStackHint = stacks;
|
||||
dcb.maxLocalsHint = locals;
|
||||
}
|
||||
|
||||
private UnboundAttribute<CodeAttribute> content = null;
|
||||
|
||||
private void writeExceptionHandlers(BufWriterImpl buf) {
|
||||
@ -319,6 +326,8 @@ public final class DirectCodeBuilder
|
||||
if (codeMatch) {
|
||||
var originalAttribute = (CodeImpl) original;
|
||||
buf.writeU2U2(originalAttribute.maxStack(), originalAttribute.maxLocals());
|
||||
} else if (maxLocalsHint >= 0 && maxStackHint >= 0) {
|
||||
buf.writeU2U2(maxStackHint, maxLocalsHint);
|
||||
} else {
|
||||
StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf);
|
||||
buf.writeU2U2(cntr.maxStack(), cntr.maxLocals());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user