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
81 changes: 53 additions & 28 deletions src/java.base/share/classes/java/lang/Module.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
Expand Down Expand Up @@ -40,7 +40,6 @@
import java.net.URI;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -69,6 +68,8 @@
import jdk.internal.module.Resources;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.DontInline;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;

/**
Expand Down Expand Up @@ -176,6 +177,7 @@ public final class Module implements AnnotatedElement {
* @see ClassLoader#getUnnamedModule()
* @jls 7.7.5 Unnamed Modules
*/
@ForceInline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the ensureNativeAccess code only depend on this one? Also, I'm having an hard time thinking that C2 can't inline this simple method? Isn't this an "accessor" ?

public boolean isNamed() {
return name != null;
}
Expand All @@ -186,6 +188,7 @@ public boolean isNamed() {
*
* @return The module name
*/
@ForceInline
public String getName() {
return name;
}
Expand All @@ -195,6 +198,7 @@ public String getName() {
*
* @return The class loader for this module
*/
@ForceInline
public ClassLoader getClassLoader() {
return loader;
}
Expand All @@ -205,6 +209,7 @@ public ClassLoader getClassLoader() {
*
* @return The module descriptor for this module
*/
@ForceInline
public ModuleDescriptor getDescriptor() {
return descriptor;
}
Expand All @@ -224,6 +229,7 @@ public ModuleDescriptor getDescriptor() {
*
* @see java.lang.reflect.Proxy
*/
@ForceInline
public ModuleLayer getLayer() {
if (isNamed()) {
ModuleLayer layer = this.layer;
Expand Down Expand Up @@ -253,6 +259,7 @@ Module implAddEnableNativeAccess() {
* @return {@code true} if this module can access <em>restricted</em> methods.
* @since 22
*/
@ForceInline
public boolean isNativeAccessEnabled() {
Module target = moduleForNativeAccess();
return EnableNativeAccess.isNativeAccessEnabled(target);
Expand All @@ -269,8 +276,9 @@ private EnableNativeAccess() {}
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final long FIELD_OFFSET = UNSAFE.objectFieldOffset(Module.class, "enableNativeAccess");

@ForceInline
private static boolean isNativeAccessEnabled(Module target) {
return UNSAFE.getBooleanVolatile(target, FIELD_OFFSET);
return target.enableNativeAccess || UNSAFE.getBooleanVolatile(target, FIELD_OFFSET);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tries plain memory semantics first.

}

// Atomically sets enableNativeAccess if not already set
Expand All @@ -282,53 +290,70 @@ private static boolean trySetEnableNativeAccess(Module target) {

// Returns the Module object that holds the enableNativeAccess
// flag for this module.
@ForceInline
private Module moduleForNativeAccess() {
return isNamed() ? this : ALL_UNNAMED_MODULE;
}

// This is invoked from Reflection.ensureNativeAccess
@ForceInline
void ensureNativeAccess(Class<?> owner, String methodName, Class<?> currentClass, boolean jni) {
// The target module whose enableNativeAccess flag is ensured
Module target = moduleForNativeAccess();
ModuleBootstrap.IllegalNativeAccess illegalNativeAccess = ModuleBootstrap.illegalNativeAccess();
if (illegalNativeAccess != ModuleBootstrap.IllegalNativeAccess.ALLOW &&
!EnableNativeAccess.isNativeAccessEnabled(target)) {
String mod = isNamed() ? "module " + getName() : "an unnamed module";
if (currentClass != null) {
// try to extract location of the current class (e.g. jar or folder)
CodeSource cs = currentClass.getProtectionDomain().getCodeSource();
if (cs != null) {
URL url = cs.getLocation();
if (url != null) {
mod += " (" + url + ")";
}
}
}
if (illegalNativeAccess == ModuleBootstrap.IllegalNativeAccess.DENY) {
throw new IllegalCallerException("Illegal native access from " + mod);
} else if (EnableNativeAccess.trySetEnableNativeAccess(target)) {
// warn and set flag, so that only one warning is reported per module
String cls = owner.getName();
String mtd = cls + "::" + methodName;
String modflag = isNamed() ? getName() : "ALL-UNNAMED";
String caller = currentClass != null ? currentClass.getName() : "code";
if (jni) {
VM.initialErr().printf("""
ensureNativeAccessSlowPath(owner, methodName, currentClass, jni, target, illegalNativeAccess);
}
}

@DontInline
void ensureNativeAccessSlowPath(Class<?> owner,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is slow anyhow so we do not need it to be inlined.

String methodName,
Class<?> currentClass,
boolean jni,
Module target,
ModuleBootstrap.IllegalNativeAccess illegalNativeAccess) {
String modDeclaredLabel = modDeclaredLabel(currentClass);
if (illegalNativeAccess == ModuleBootstrap.IllegalNativeAccess.DENY) {
throw new IllegalCallerException("Illegal native access from " + modDeclaredLabel);
} else if (EnableNativeAccess.trySetEnableNativeAccess(target)) {
// warn and set flag, so that only one warning is reported per module
String cls = owner.getName();
String mtd = cls + "::" + methodName;
String modFlag = isNamed() ? getName() : "ALL-UNNAMED";
String caller = currentClass != null ? currentClass.getName() : "code";
if (jni) {
VM.initialErr().printf("""
WARNING: A native method in %s has been bound
WARNING: %s is declared in %s
WARNING: Use --enable-native-access=%s to avoid a warning for native methods declared in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
%n""", cls, mtd, mod, modflag);
} else {
VM.initialErr().printf("""
%n""", cls, mtd, modDeclaredLabel, modFlag);
} else {
VM.initialErr().printf("""
WARNING: A restricted method in %s has been called
WARNING: %s has been called by %s in %s
WARNING: Use --enable-native-access=%s to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
%n""", cls, mtd, caller, mod, modflag);
%n""", cls, mtd, caller, modDeclaredLabel, modFlag);
}
}
}

private String modDeclaredLabel(Class<?> currentClass) {
String label = isNamed() ? "module " + getName() : "an unnamed module";
if (currentClass != null) {
// try to extract location of the current class (e.g. jar or folder)
CodeSource cs = currentClass.getProtectionDomain().getCodeSource();
if (cs != null) {
URL url = cs.getLocation();
if (url != null) {
label += " (" + url + ")";
}
}
}
return label;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/java.base/share/classes/java/lang/Object.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
Expand All @@ -25,6 +25,7 @@

package java.lang;

import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;

/**
Expand All @@ -40,6 +41,7 @@ public class Object {
/**
* Constructs a new object.
*/
@ForceInline
@IntrinsicCandidate
public Object() {}

Expand Down
2 changes: 2 additions & 0 deletions src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import jdk.internal.vm.ContinuationScope;
import jdk.internal.vm.StackableScope;
import jdk.internal.vm.ThreadContainer;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.vm.annotation.Stable;
import sun.reflect.annotation.AnnotationType;
Expand Down Expand Up @@ -2080,6 +2081,7 @@ public boolean addEnableNativeAccess(ModuleLayer layer, String name) {
public void addEnableNativeAccessToAllUnnamed() {
Module.implAddEnableNativeAccessToAllUnnamed();
}
@ForceInline
public void ensureNativeAccess(Module m, Class<?> owner, String methodName, Class<?> currentClass, boolean jni) {
m.ensureNativeAccess(owner, methodName, currentClass, jni);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ private NativeMemorySegmentImpl reinterpretInternal(Class<?> callerClass, long n
}

// Using a static helper method ensures there is no unintended lambda capturing of `this`
@ForceInline
private static Runnable cleanupAction(long address, long newSize, Consumer<MemorySegment> cleanup) {
return cleanup != null ?
() -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address, newSize)) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ public void checkValidStateRaw() {
* @throws IllegalStateException if this session is already closed or if this is
* a confined session and this method is called outside the owner thread.
*/
@ForceInline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume this is added because it's called by the reinterpret implementation?

public void checkValidState() {
try {
checkValidStateRaw();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@
*/
public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl permits MappedMemorySegmentImpl {

private static final boolean ADDRESS_SIZE_IS_4 =
Unsafe.getUnsafe().addressSize() == 4;

final long min;

@ForceInline
NativeMemorySegmentImpl(long min, long length, boolean readOnly, MemorySessionImpl scope) {
super(length, readOnly, scope);
this.min = (Unsafe.getUnsafe().addressSize() == 4)
this.min = ADDRESS_SIZE_IS_4
// On 32-bit systems, normalize the upper unused 32-bits to zero
? min & 0x0000_0000_FFFF_FFFFL
// On 64-bit systems, all the bits are used
Expand Down Expand Up @@ -77,6 +80,7 @@ ByteBuffer makeByteBuffer() {
return NIO_ACCESS.newDirectByteBuffer(min, (int) this.length, null, this);
}

@ForceInline
@Override
public boolean isNative() {
return true;
Expand All @@ -93,6 +97,7 @@ public Object unsafeGetBase() {
}

@Override
@ForceInline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is needed -- this is an "accessor" method - C2 typically inline those. But, do we depend on maxAlignMask for reinterpret?

public long maxAlignMask() {
return 0;
}
Expand Down
16 changes: 12 additions & 4 deletions src/java.base/share/classes/jdk/internal/misc/Unsafe.java
Original file line number Diff line number Diff line change
Expand Up @@ -3567,6 +3567,7 @@ public final long getLongUnaligned(Object o, long offset) {
* @return the value fetched from the indicated object
* @since 9
*/
@ForceInline
Copy link
Contributor Author

@minborg minborg Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These annotations are not totally out of the question as the corresponding methods (e.g. public final long getLongUnaligned(Object o, long offset) are @IntrinsicCandidate and will indeed be inlined because of that. So, this creates symmetry with respect to inlining.

public final long getLongUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getLongUnaligned(o, offset));
}
Expand All @@ -3587,6 +3588,7 @@ public final int getIntUnaligned(Object o, long offset) {
}
}
/** @see #getLongUnaligned(Object, long, boolean) */
@ForceInline
public final int getIntUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getIntUnaligned(o, offset));
}
Expand All @@ -3602,6 +3604,7 @@ public final short getShortUnaligned(Object o, long offset) {
}
}
/** @see #getLongUnaligned(Object, long, boolean) */
@ForceInline
public final short getShortUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getShortUnaligned(o, offset));
}
Expand All @@ -3618,6 +3621,7 @@ public final char getCharUnaligned(Object o, long offset) {
}

/** @see #getLongUnaligned(Object, long, boolean) */
@ForceInline
public final char getCharUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getCharUnaligned(o, offset));
}
Expand Down Expand Up @@ -3688,6 +3692,7 @@ public final void putLongUnaligned(Object o, long offset, long x) {
* {@link NullPointerException}
* @since 9
*/
@ForceInline
public final void putLongUnaligned(Object o, long offset, long x, boolean bigEndian) {
putLongUnaligned(o, offset, convEndian(bigEndian, x));
}
Expand All @@ -3710,6 +3715,7 @@ public final void putIntUnaligned(Object o, long offset, int x) {
}
}
/** @see #putLongUnaligned(Object, long, long, boolean) */
@ForceInline
public final void putIntUnaligned(Object o, long offset, int x, boolean bigEndian) {
putIntUnaligned(o, offset, convEndian(bigEndian, x));
}
Expand All @@ -3726,6 +3732,7 @@ public final void putShortUnaligned(Object o, long offset, short x) {
}
}
/** @see #putLongUnaligned(Object, long, long, boolean) */
@ForceInline
public final void putShortUnaligned(Object o, long offset, short x, boolean bigEndian) {
putShortUnaligned(o, offset, convEndian(bigEndian, x));
}
Expand All @@ -3736,6 +3743,7 @@ public final void putCharUnaligned(Object o, long offset, char x) {
putShortUnaligned(o, offset, (short)x);
}
/** @see #putLongUnaligned(Object, long, long, boolean) */
@ForceInline
public final void putCharUnaligned(Object o, long offset, char x, boolean bigEndian) {
putCharUnaligned(o, offset, convEndian(bigEndian, x));
}
Expand Down Expand Up @@ -3829,10 +3837,10 @@ private void putShortParts(Object o, long offset, byte i0, byte i1) {
private static long toUnsignedLong(int n) { return n & 0xffffffffl; }

// Maybe byte-reverse an integer
private static char convEndian(boolean big, char n) { return big == BIG_ENDIAN ? n : Character.reverseBytes(n); }
private static short convEndian(boolean big, short n) { return big == BIG_ENDIAN ? n : Short.reverseBytes(n) ; }
private static int convEndian(boolean big, int n) { return big == BIG_ENDIAN ? n : Integer.reverseBytes(n) ; }
private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; }
@ForceInline private static char convEndian(boolean big, char n) { return big == BIG_ENDIAN ? n : Character.reverseBytes(n); }
@ForceInline private static short convEndian(boolean big, short n) { return big == BIG_ENDIAN ? n : Short.reverseBytes(n) ; }
@ForceInline private static int convEndian(boolean big, int n) { return big == BIG_ENDIAN ? n : Integer.reverseBytes(n) ; }
@ForceInline private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; }



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.CDS;
import jdk.internal.perf.PerfCounter;
import jdk.internal.vm.annotation.ForceInline;

/**
* Initializes/boots the module system.
Expand Down Expand Up @@ -820,6 +821,7 @@ public enum IllegalNativeAccess {
DENY
}

@ForceInline
public static IllegalNativeAccess illegalNativeAccess() {
return ILLEGAL_NATIVE_ACCESS;
}
Expand Down Expand Up @@ -887,6 +889,7 @@ private static Set<String> decodeEnableNativeAccess() {
/**
* Process the --illegal-native-access option (and its default).
*/
@ForceInline
private static IllegalNativeAccess addIllegalNativeAccess() {
String value = getAndRemoveProperty("jdk.module.illegal.native.access");
// don't use a switch: bootstrapping issues!
Expand Down
Loading