Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 34 additions & 11 deletions src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

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;
Expand All @@ -48,6 +50,7 @@
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;
Expand Down Expand Up @@ -103,6 +106,13 @@ private 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;
Expand Down Expand Up @@ -482,8 +492,11 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
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)
Expand All @@ -494,9 +507,12 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
.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);
Expand All @@ -509,6 +525,7 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
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;
Expand Down Expand Up @@ -541,7 +558,7 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
} 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 ||
Expand Down Expand Up @@ -570,8 +587,9 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
"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)
Expand All @@ -580,6 +598,7 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
"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);
Expand Down Expand Up @@ -648,18 +667,19 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
"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)
.checkcast(CD_Character)
.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 ||
Expand Down Expand Up @@ -688,9 +708,12 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
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
};
}

Expand All @@ -702,7 +725,7 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas
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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<>();
Expand All @@ -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,
Expand Down Expand Up @@ -173,6 +174,12 @@ public MethodInfo methodInfo() {
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) {
Expand Down Expand Up @@ -319,6 +326,8 @@ private void writeCounters(boolean codeMatch, BufWriterImpl buf) {
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());
Expand Down