1 /*
2 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package jdk.internal.classfile.impl;
26
27 import java.lang.classfile.constantpool.ConstantPoolBuilder;
28 import java.lang.classfile.constantpool.Utf8Entry;
29 import java.util.Arrays;
30
31 import static java.lang.classfile.ClassFile.*;
32
33 /**
34 * An interface to obtain field properties for direct class builders.
35 * Required to filter strict instance fields for stack map generation.
36 * Public for benchmark access.
37 */
38 public sealed interface WritableField extends Util.Writable
39 permits FieldImpl, DirectFieldBuilder {
40 Utf8Entry fieldName();
41 Utf8Entry fieldType();
42 int fieldFlags();
43
44 static WritableField.UnsetField[] filterStrictInstanceFields(ConstantPoolBuilder cpb, WritableField[] array, int count) {
45 // assume there's no toctou for trusted incoming array
46 int size = 0;
47 for (int i = 0; i < count; i++) {
48 var field = array[i];
49 if ((field.fieldFlags() & (ACC_STATIC | ACC_STRICT_INIT)) == ACC_STRICT_INIT) {
50 size++;
51 }
52 }
53 if (size == 0)
54 return UnsetField.EMPTY_ARRAY;
55 UnsetField[] ret = new UnsetField[size];
56 int j = 0;
57 for (int i = 0; i < count; i++) {
58 var field = array[i];
59 if ((field.fieldFlags() & (ACC_STATIC | ACC_STRICT_INIT)) == ACC_STRICT_INIT) {
60 ret[j++] = new UnsetField(AbstractPoolEntry.maybeClone(cpb, field.fieldName()),
61 AbstractPoolEntry.maybeClone(cpb, field.fieldType()));
62 }
63 }
64 assert j == size : "toctou: " + j + " != " + size;
65 Arrays.sort(ret);
66 return ret;
67 }
68
69 // The captured information of unset fields, pool entries localized to class writing context
70 // avoid creating NAT until we need to write the fields to stack maps
71 record UnsetField(Utf8Entry name, Utf8Entry type) implements Comparable<UnsetField> {
72 public UnsetField {
73 assert Util.checkConstantPoolsCompatible(name.constantPool(), type.constantPool());
74 }
75 public static final UnsetField[] EMPTY_ARRAY = new UnsetField[0];
76
77 public static UnsetField[] copyArray(UnsetField[] incoming, int resultLen) {
78 assert resultLen <= incoming.length : resultLen + " > " + incoming.length;
79 return resultLen == 0 ? EMPTY_ARRAY : Arrays.copyOf(incoming, resultLen, UnsetField[].class);
80 }
81
82 public static boolean matches(UnsetField[] one, int sizeOne, UnsetField[] two, int sizeTwo) {
83 if (sizeOne != sizeTwo)
84 return false;
85 for (int i = 0; i < sizeOne; i++) {
86 if (!one[i].equals(two[i])) {
87 return false;
88 }
89 }
90 return true;
91 }
92
93 // Warning: inconsistent with equals (which uses UTF8 object equality)
94 @Override
95 public int compareTo(UnsetField o) {
96 assert Util.checkConstantPoolsCompatible(name.constantPool(), o.name.constantPool());
97 var ret = Integer.compare(name.index(), o.name.index());
98 if (ret != 0)
99 return ret;
100 return Integer.compare(type.index(), o.type.index());
101 }
102 }
103 }