< prev index next > src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
Print this page
/*
! * 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
/*
! * Copyright (c) 2022, 2025, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*;
import static java.util.Objects.requireNonNull;
public class StackMapDecoder {
! private static final int
SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
SAME_EXTENDED = 251;
private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
private final ClassReader classReader;
private final int pos;
private final LabelContext ctx;
import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
import java.lang.classfile.constantpool.ClassEntry;
+ import java.lang.classfile.constantpool.NameAndTypeEntry;
+ import java.lang.classfile.constantpool.PoolEntry;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
+ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+ import jdk.internal.access.SharedSecrets;
+
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*;
import static java.util.Objects.requireNonNull;
public class StackMapDecoder {
! static final int
+ ASSERT_UNSET_FIELDS = 246,
SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
SAME_EXTENDED = 251;
+ private static final int RESERVED_TAGS_UPPER_LIMIT = ASSERT_UNSET_FIELDS; // not inclusive
private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
private final ClassReader classReader;
private final int pos;
private final LabelContext ctx;
bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget()));
default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag());
}
}
List<StackMapFrameInfo> entries() {
p = pos;
List<VerificationTypeInfo> locals = initFrameLocals, stack = List.of();
int bci = -1;
! var entries = new StackMapFrameInfo[u2()];
! for (int ei = 0; ei < entries.length; ei++) {
int frameType = classReader.readU1(p++);
if (frameType < 64) {
bci += frameType + 1;
stack = List.of();
} else if (frameType < 128) {
bci += frameType - 63;
stack = List.of(readVerificationTypeInfo());
} else {
! if (frameType < SAME_LOCALS_1_STACK_ITEM_EXTENDED)
throw new IllegalArgumentException("Invalid stackmap frame type: " + frameType);
bci += u2() + 1;
if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
stack = List.of(readVerificationTypeInfo());
} else if (frameType < SAME_EXTENDED) {
locals = locals.subList(0, locals.size() + frameType - SAME_EXTENDED);
bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget()));
default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag());
}
}
+ // Copied from BoundAttribute
+ <E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) {
+ int cnt = classReader.readU2(p);
+ p += 2;
+ var entries = new Object[cnt];
+ int end = p + (cnt * 2);
+ for (int i = 0; p < end; i++, p += 2) {
+ entries[i] = classReader.readEntry(p, type);
+ }
+ return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
+ }
+
List<StackMapFrameInfo> entries() {
p = pos;
List<VerificationTypeInfo> locals = initFrameLocals, stack = List.of();
+ List<NameAndTypeEntry> unsetFields = List.of();
int bci = -1;
! int len = u2();
! var entries = new ArrayList<StackMapFrameInfo>(len);
+ List<List<NameAndTypeEntry>> deferredUnsetFields = new ArrayList<>();
+ for (int ei = 0; ei < len; ei++) {
+ var oldLocals = locals;
+ var oldStack = stack;
int frameType = classReader.readU1(p++);
if (frameType < 64) {
bci += frameType + 1;
stack = List.of();
} else if (frameType < 128) {
bci += frameType - 63;
stack = List.of(readVerificationTypeInfo());
} else {
! if (frameType < RESERVED_TAGS_UPPER_LIMIT)
throw new IllegalArgumentException("Invalid stackmap frame type: " + frameType);
+ if (frameType == ASSERT_UNSET_FIELDS) {
+ unsetFields = readEntryList(p, NameAndTypeEntry.class);
+ p += 2 + unsetFields.size() * 2;
+ deferredUnsetFields.add(unsetFields);
+ continue; // defer entry until we can get the bci
+ }
bci += u2() + 1;
if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
stack = List.of(readVerificationTypeInfo());
} else if (frameType < SAME_EXTENDED) {
locals = locals.subList(0, locals.size() + frameType - SAME_EXTENDED);
newStack[i] = readVerificationTypeInfo();
locals = List.of(newLocals);
stack = List.of(newStack);
}
}
! entries[ei] = new StackMapFrameImpl(frameType,
! ctx.getLabel(bci),
locals,
! stack);
}
! return List.of(entries);
}
private VerificationTypeInfo readVerificationTypeInfo() {
int tag = classReader.readU1(p++);
return switch (tag) {
newStack[i] = readVerificationTypeInfo();
locals = List.of(newLocals);
stack = List.of(newStack);
}
}
! Label label = ctx.getLabel(bci);
! if (!deferredUnsetFields.isEmpty()) {
+ // technically we only have one assert at once, just in case
+ // of duplicate asserts...
+ for (var deferredList : deferredUnsetFields) {
+ entries.add(new StackMapFrameImpl(ASSERT_UNSET_FIELDS,
+ label, oldLocals, oldStack, deferredList));
+ }
+ deferredUnsetFields.clear();
+ }
+ entries.add(new StackMapFrameImpl(frameType,
+ label,
locals,
! stack));
}
! return List.copyOf(entries);
}
private VerificationTypeInfo readVerificationTypeInfo() {
int tag = classReader.readU1(p++);
return switch (tag) {
}
public static record StackMapFrameImpl(int frameType,
Label target,
List<VerificationTypeInfo> locals,
! List<VerificationTypeInfo> stack)
implements StackMapFrameInfo {
public StackMapFrameImpl {
requireNonNull(target);
locals = List.copyOf(locals);
stack = List.copyOf(stack);
}
}
}
}
public static record StackMapFrameImpl(int frameType,
Label target,
List<VerificationTypeInfo> locals,
! List<VerificationTypeInfo> stack,
+ List<NameAndTypeEntry> unsetFields)
implements StackMapFrameInfo {
public StackMapFrameImpl {
requireNonNull(target);
locals = List.copyOf(locals);
stack = List.copyOf(stack);
+ unsetFields = List.copyOf(unsetFields);
+ }
+
+ public StackMapFrameImpl(int frameType,
+ Label target,
+ List<VerificationTypeInfo> locals,
+ List<VerificationTypeInfo> stack) {
+ this(frameType, target, locals, stack, List.of());
}
}
}
< prev index next >