Skip to content

Commit acce344

Browse files
committed
Image size: stuff preserved bit into existing bitsets for JNI methods/fields
1 parent f8cfda4 commit acce344

File tree

6 files changed

+80
-39
lines changed

6 files changed

+80
-39
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleClass.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,21 @@
3939
/**
4040
* Information on a class that can be looked up and accessed via JNI.
4141
*/
42-
public final class JNIAccessibleClass extends JNIAccessibleElement {
42+
public final class JNIAccessibleClass implements PreservableJNIElement {
4343
private final Class<?> classObject;
4444
private EconomicMap<JNIAccessibleMethodDescriptor, JNIAccessibleMethod> methods;
4545
private EconomicMap<CharSequence, JNIAccessibleField> fields;
46+
private boolean preserved;
4647

4748
@Platforms(HOSTED_ONLY.class)
4849
public JNIAccessibleClass(Class<?> clazz, boolean preserved) {
49-
super(preserved);
5050
assert clazz != null;
5151
this.classObject = clazz;
52+
this.preserved = preserved;
5253
}
5354

5455
@Platforms(HOSTED_ONLY.class)
5556
JNIAccessibleClass() {
56-
super(false);
5757
/* For negative queries */
5858
this.classObject = null;
5959
}
@@ -127,4 +127,17 @@ public JNIAccessibleMethod getMethod(JNIAccessibleMethodDescriptor descriptor) {
127127
String getJNIName() {
128128
return ClassNameSupport.reflectionNameToJNIName(classObject.getName());
129129
}
130+
131+
@Override
132+
public boolean isPreserved() {
133+
return preserved;
134+
}
135+
136+
@Override
137+
public void reportReregistered(boolean updatedPreserved) {
138+
// State can only ever go from "preserved" to "not preserved".
139+
if (!updatedPreserved) {
140+
this.preserved = false;
141+
}
142+
}
130143
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,21 @@
4747
/**
4848
* Information on a field that can be looked up and accessed via JNI.
4949
*/
50-
public final class JNIAccessibleField extends JNIAccessibleMember {
50+
public final class JNIAccessibleField extends JNIAccessibleMember implements PreservableJNIElement {
5151
/* 10000000...0 */
5252
private static final UnsignedWord ID_STATIC_FLAG = Word.unsigned(-1L).unsignedShiftRight(1).add(1);
5353
/* 01000000...0 */
54-
private static final UnsignedWord ID_OBJECT_FLAG = ID_STATIC_FLAG.unsignedShiftRight(1);
54+
private static final UnsignedWord ID_PRESERVED_FLAG = ID_STATIC_FLAG.unsignedShiftRight(1);
5555
/* 00100000...0 */
56-
private static final UnsignedWord ID_NEGATIVE_FLAG = ID_OBJECT_FLAG.unsignedShiftRight(1);
56+
private static final UnsignedWord ID_NEGATIVE_FLAG = ID_PRESERVED_FLAG.unsignedShiftRight(1);
5757
/* 00010000...0 */
5858
private static final UnsignedWord ID_LAYER_NUMBER_MASK = ID_NEGATIVE_FLAG.unsignedShiftRight(1);
5959
private static final int ID_LAYER_NUMBER_SHIFT = 60;
6060
/* 00001111...1 */
6161
private static final UnsignedWord ID_OFFSET_MASK = ID_LAYER_NUMBER_MASK.subtract(1);
6262

6363
public static JNIAccessibleField negativeFieldQuery(JNIAccessibleClass jniClass) {
64-
return new JNIAccessibleField(false, jniClass, null, 0);
64+
return new JNIAccessibleField(jniClass, null, 0, false);
6565
}
6666

6767
/**
@@ -99,31 +99,33 @@ private static int getLayerNumberFromId(UnsignedWord id) {
9999
}
100100
}
101101

102-
@Platforms(HOSTED_ONLY.class) private final UnsignedWord flags;
102+
@Platforms(HOSTED_ONLY.class) private UnsignedWord flags;
103103

104104
/**
105105
* Represents the {@link JNIFieldId} of the field.
106106
*
107107
* From left (MSB) to right (LSB):
108108
* <ul>
109109
* <li>1 bit for a flag indicating whether the field is static</li>
110-
* <li>1 bit for a flag indicating whether the field is an object reference</li>
110+
* <li>1 bit for a flag indicating whether the field is preserved</li>
111111
* <li>1 bit for a flag indicating whether the field is a negative query</li>
112-
* <li>Remaining 61 bits for (unsigned) offset in the object</li>
112+
* <li>1 bit for an unsigned integer indicating the layer number</li>
113+
* <li>Remaining 60 bits for (unsigned) offset in the object</li>
113114
* </ul>
114115
*/
115116
@UnknownPrimitiveField(availability = ReadyForCompilation.class)//
116117
private UnsignedWord id = Word.zero();
117118

118119
@Platforms(HOSTED_ONLY.class)
119-
public JNIAccessibleField(boolean preserved, JNIAccessibleClass declaringClass, JavaKind kind, int modifiers) {
120-
super(preserved, declaringClass);
120+
public JNIAccessibleField(JNIAccessibleClass declaringClass, JavaKind kind, int modifiers, boolean preserved) {
121+
super(declaringClass);
121122

122123
UnsignedWord bits = Modifier.isStatic(modifiers) ? ID_STATIC_FLAG : Word.zero();
123124
if (kind == null) {
124125
bits = bits.or(ID_NEGATIVE_FLAG);
125-
} else if (kind.isObject()) {
126-
bits = bits.or(ID_OBJECT_FLAG);
126+
}
127+
if (preserved) {
128+
bits = bits.or(ID_PRESERVED_FLAG);
127129
}
128130
this.flags = bits;
129131
}
@@ -161,4 +163,18 @@ public void finishBeforeCompilation(int offset, int layerNumber, EconomicSet<Cla
161163
}
162164
setHidingSubclasses(hidingSubclasses);
163165
}
166+
167+
@Override
168+
public boolean isPreserved() {
169+
return id.and(ID_PRESERVED_FLAG).notEqual(0);
170+
}
171+
172+
@Platforms(HOSTED_ONLY.class)
173+
@Override
174+
public void reportReregistered(boolean updatedPreserved) {
175+
// State can only ever go from "preserved" to "not preserved".
176+
if (!updatedPreserved) {
177+
flags = flags.and(ID_PRESERVED_FLAG.not());
178+
}
179+
}
164180
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMember.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,13 @@
3131
import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation;
3232
import com.oracle.svm.core.heap.UnknownObjectField;
3333

34-
abstract class JNIAccessibleMember extends JNIAccessibleElement {
34+
abstract class JNIAccessibleMember {
3535
private final JNIAccessibleClass declaringClass;
3636

3737
@UnknownObjectField(fullyQualifiedTypes = "org.graalvm.collections.EconomicMapImpl", canBeNull = true, availability = ReadyForCompilation.class) //
3838
private EconomicSet<Class<?>> hidingSubclasses;
3939

40-
JNIAccessibleMember(boolean preserved, JNIAccessibleClass declaringClass) {
41-
super(preserved);
40+
JNIAccessibleMember(JNIAccessibleClass declaringClass) {
4241
this.declaringClass = declaringClass;
4342
}
4443

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
/**
4949
* Information on a method that can be looked up and called via JNI.
5050
*/
51-
public final class JNIAccessibleMethod extends JNIAccessibleMember {
51+
public final class JNIAccessibleMethod extends JNIAccessibleMember implements PreservableJNIElement {
5252
public static final int VTABLE_INDEX_STATICALLY_BOUND_METHOD = -1;
5353
public static final int VTABLE_INDEX_NOT_YET_COMPUTED = -2;
5454
public static final int INTERFACE_TYPEID_CLASS_TABLE = -1;
@@ -57,7 +57,7 @@ public final class JNIAccessibleMethod extends JNIAccessibleMember {
5757
public static final int NEW_OBJECT_TARGET_INVALID_FOR_ABSTRACT_TYPE = -1;
5858

5959
public static JNIAccessibleMethod negativeMethodQuery(JNIAccessibleClass jniClass) {
60-
return new JNIAccessibleMethod(false, jniClass, RuntimeMetadataDecoderImpl.NEGATIVE_FLAG_MASK);
60+
return new JNIAccessibleMethod(jniClass, RuntimeMetadataDecoderImpl.NEGATIVE_FLAG_MASK, false);
6161
}
6262

6363
@Platforms(HOSTED_ONLY.class)
@@ -79,7 +79,7 @@ public static ResolvedJavaField getCallVariantWrapperField(MetaAccessProvider me
7979
return metaAccess.lookupJavaField(ReflectionUtil.lookupField(JNIAccessibleMethod.class, name.toString()));
8080
}
8181

82-
private final int modifiers;
82+
private int modifiers;
8383
@UnknownPrimitiveField(availability = ReadyForCompilation.class)//
8484
private int vtableIndex = VTABLE_INDEX_NOT_YET_COMPUTED;
8585
@UnknownPrimitiveField(availability = ReadyForCompilation.class)//
@@ -104,9 +104,10 @@ public static ResolvedJavaField getCallVariantWrapperField(MetaAccessProvider me
104104
@SuppressWarnings("unused") private CodePointer valistNonvirtualWrapper;
105105

106106
@Platforms(HOSTED_ONLY.class)
107-
public JNIAccessibleMethod(boolean preserved, JNIAccessibleClass declaringClass, int modifiers) {
108-
super(preserved, declaringClass);
109-
this.modifiers = modifiers;
107+
public JNIAccessibleMethod(JNIAccessibleClass declaringClass, int modifiers, boolean preserved) {
108+
super(declaringClass);
109+
assert (modifiers & RuntimeMetadataDecoderImpl.PRESERVED_FLAG_MASK) == 0;
110+
this.modifiers = modifiers | (preserved ? RuntimeMetadataDecoderImpl.PRESERVED_FLAG_MASK : 0);
110111
}
111112

112113
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@@ -172,4 +173,17 @@ public void finishBeforeCompilation(EconomicSet<Class<?>> hidingSubclasses, int
172173
this.valistNonvirtualWrapper = valistNonvirtual;
173174
setHidingSubclasses(hidingSubclasses);
174175
}
176+
177+
@Override
178+
public boolean isPreserved() {
179+
return (modifiers & RuntimeMetadataDecoderImpl.PRESERVED_FLAG_MASK) != 0;
180+
}
181+
182+
@Override
183+
public void reportReregistered(boolean updatedPreserved) {
184+
// State can only ever go from "preserved" to "not preserved".
185+
if (!updatedPreserved) {
186+
modifiers = modifiers & (~RuntimeMetadataDecoderImpl.PRESERVED_FLAG_MASK);
187+
}
188+
}
175189
}
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,20 @@
2424
*/
2525
package com.oracle.svm.core.jni.access;
2626

27-
public abstract class JNIAccessibleElement {
28-
private volatile boolean preserved;
27+
import org.graalvm.nativeimage.Platform;
28+
import org.graalvm.nativeimage.Platforms;
2929

30-
protected JNIAccessibleElement(boolean preserved) {
31-
this.preserved = preserved;
32-
}
30+
/**
31+
* Represents a JNI element that can be included in the image by
32+
* {@link com.oracle.svm.core.SubstrateOptions#Preserve}. Records whether it was preserved or
33+
* actually registered in the image.
34+
*
35+
* @since 25.1
36+
*/
37+
public interface PreservableJNIElement {
3338

34-
public void reportReregistered(boolean reregisterPreserved) {
35-
// State can only ever go from "preserved" to "not preserved".
36-
if (!reregisterPreserved) {
37-
this.preserved = false;
38-
}
39-
}
39+
boolean isPreserved();
4040

41-
public boolean isPreserved() {
42-
return preserved;
43-
}
41+
@Platforms(Platform.HOSTED_ONLY.class)
42+
void reportReregistered(boolean updatedPreserved);
4443
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ public void addMethod(Executable method, boolean preserved, DuringAnalysisAccess
475475
if (!Modifier.isStatic(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers())) {
476476
nonvirtualVariantWrappers = createJavaCallVariantWrappers(access, callWrapperMethod.getSignature(), true, method);
477477
}
478-
JNIAccessibleMethod jniMethod = new JNIAccessibleMethod(preserved, jniClass, method.getModifiers());
478+
JNIAccessibleMethod jniMethod = new JNIAccessibleMethod(jniClass, method.getModifiers(), preserved);
479479
calledJavaMethods.add(new JNICallableJavaMethod(descriptor, jniMethod, targetMethod, callWrapperMethod, newObjectMethod, variantWrappers, nonvirtualVariantWrappers));
480480
return jniMethod;
481481
});
@@ -513,7 +513,7 @@ private void addField(Field reflField, boolean preserved, boolean writable, Duri
513513
}
514514
JNIAccessibleClass jniClass = addClass(reflField.getDeclaringClass(), preserved, access);
515515
AnalysisField field = access.getMetaAccess().lookupJavaField(reflField);
516-
jniClass.addOrUpdateField(field.getName(), preserved, _ -> new JNIAccessibleField(preserved, jniClass, field.getJavaKind(), field.getModifiers()));
516+
jniClass.addOrUpdateField(field.getName(), preserved, _ -> new JNIAccessibleField(jniClass, field.getJavaKind(), field.getModifiers(), preserved));
517517
field.registerAsRead("it is registered for as JNI accessed");
518518
if (writable) {
519519
field.registerAsWritten("it is registered as JNI writable");

0 commit comments

Comments
 (0)