1 /* 2 * Copyright (c) 1996, 2023, 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 26 package jdk.internal.misc; 27 28 import static java.lang.Thread.State.*; 29 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.Map; 34 35 import jdk.internal.access.SharedSecrets; 36 import jdk.internal.vm.annotation.Stable; 37 import sun.nio.ch.FileChannelImpl; 38 39 public class VM { 40 41 // the init level when the VM is fully initialized 42 private static final int JAVA_LANG_SYSTEM_INITED = 1; 43 private static final int MODULE_SYSTEM_INITED = 2; 44 private static final int SYSTEM_LOADER_INITIALIZING = 3; 45 private static final int SYSTEM_BOOTED = 4; 46 private static final int SYSTEM_SHUTDOWN = 5; 47 48 // 0, 1, 2, ... 49 private static volatile int initLevel; 50 private static final Object lock = new Object(); 51 52 /** 53 * Sets the init level. 54 * 55 * @see java.lang.System#initPhase1 56 * @see java.lang.System#initPhase2 57 * @see java.lang.System#initPhase3 58 */ 59 public static void initLevel(int value) { 60 synchronized (lock) { 61 if (value <= initLevel || value > SYSTEM_SHUTDOWN) 62 throw new InternalError("Bad level: " + value); 63 initLevel = value; 64 lock.notifyAll(); 65 } 66 } 67 68 /** 69 * Returns the current init level. 70 */ 71 public static int initLevel() { 72 return initLevel; 73 } 74 75 /** 76 * Waits for the init level to get the given value. 77 */ 78 public static void awaitInitLevel(int value) throws InterruptedException { 79 synchronized (lock) { 80 while (initLevel < value) { 81 lock.wait(); 82 } 83 } 84 } 85 86 /** 87 * Returns {@code true} if the module system has been initialized. 88 * @see java.lang.System#initPhase2 89 */ 90 public static boolean isModuleSystemInited() { 91 return initLevel >= MODULE_SYSTEM_INITED; 92 } 93 94 private static @Stable boolean javaLangInvokeInited; 95 public static void setJavaLangInvokeInited() { 96 if (javaLangInvokeInited) { 97 throw new InternalError("java.lang.invoke already inited"); 98 } 99 javaLangInvokeInited = true; 100 } 101 102 public static boolean isJavaLangInvokeInited() { 103 return javaLangInvokeInited; 104 } 105 106 /** 107 * Returns {@code true} if the VM is fully initialized. 108 */ 109 public static boolean isBooted() { 110 return initLevel >= SYSTEM_BOOTED; 111 } 112 113 /** 114 * Set shutdown state. Shutdown completes when all registered shutdown 115 * hooks have been run. 116 * 117 * @see java.lang.Shutdown 118 */ 119 public static void shutdown() { 120 initLevel(SYSTEM_SHUTDOWN); 121 } 122 123 /** 124 * Returns {@code true} if the VM has been shutdown 125 */ 126 public static boolean isShutdown() { 127 return initLevel == SYSTEM_SHUTDOWN; 128 } 129 130 // A user-settable upper limit on the maximum amount of allocatable direct 131 // buffer memory. This value may be changed during VM initialization if 132 // "java" is launched with "-XX:MaxDirectMemorySize=<size>". 133 // 134 // The initial value of this field is arbitrary; during JRE initialization 135 // it will be reset to the value specified on the command line, if any, 136 // otherwise to Runtime.getRuntime().maxMemory(). 137 // 138 private static long directMemory = 64 * 1024 * 1024; 139 140 // Returns the maximum amount of allocatable direct buffer memory. 141 // The directMemory variable is initialized during system initialization 142 // in the saveAndRemoveProperties method. 143 // 144 public static long maxDirectMemory() { 145 return directMemory; 146 } 147 148 // User-controllable flag that determines if direct buffers should be page 149 // aligned. The "-XX:+PageAlignDirectMemory" option can be used to force 150 // buffers, allocated by ByteBuffer.allocateDirect, to be page aligned. 151 @Stable 152 private static boolean pageAlignDirectMemory; 153 154 // Returns {@code true} if the direct buffers should be page aligned. This 155 // variable is initialized by saveAndRemoveProperties. 156 public static boolean isDirectMemoryPageAligned() { 157 return pageAlignDirectMemory; 158 } 159 160 private static int classFileMajorVersion; 161 private static int classFileMinorVersion; 162 private static final int PREVIEW_MINOR_VERSION = 65535; 163 164 /** 165 * Tests if the given version is a supported {@code class} 166 * file version. 167 * 168 * A {@code class} file depends on the preview features of Java SE {@code N} 169 * if the major version is {@code N} and the minor version is 65535. 170 * This method returns {@code true} if the given version is a supported 171 * {@code class} file version regardless of whether the preview features 172 * are enabled or not. 173 * 174 * @jvms 4.1 Table 4.1-A. class file format major versions 175 */ 176 public static boolean isSupportedClassFileVersion(int major, int minor) { 177 if (major < 45 || major > classFileMajorVersion) return false; 178 // for major version is between 45 and 55 inclusive, the minor version may be any value 179 if (major < 56) return true; 180 // otherwise, the minor version must be 0 or 65535 181 return minor == 0 || minor == PREVIEW_MINOR_VERSION; 182 } 183 184 /** 185 * Tests if the given version is a supported {@code class} 186 * file version for module descriptor. 187 * 188 * major.minor version >= 53.0 189 */ 190 public static boolean isSupportedModuleDescriptorVersion(int major, int minor) { 191 if (major < 53 || major > classFileMajorVersion) return false; 192 // for major version is between 45 and 55 inclusive, the minor version may be any value 193 if (major < 56) return true; 194 // otherwise, the minor version must be 0 or 65535 195 // preview features do not apply to module-info.class but JVMS allows it 196 return minor == 0 || minor == PREVIEW_MINOR_VERSION; 197 } 198 199 /** 200 * Returns true if the given class loader is the bootstrap class loader 201 * or the platform class loader. 202 */ 203 public static boolean isSystemDomainLoader(ClassLoader loader) { 204 return loader == null || loader == ClassLoader.getPlatformClassLoader(); 205 } 206 207 /** 208 * Returns the system property of the specified key saved at 209 * system initialization time. This method should only be used 210 * for the system properties that are not changed during runtime. 211 * 212 * Note that the saved system properties do not include 213 * the ones set by java.lang.VersionProps.init(). 214 */ 215 public static String getSavedProperty(String key) { 216 if (savedProps == null) 217 throw new IllegalStateException("Not yet initialized"); 218 219 return savedProps.get(key); 220 } 221 222 /** 223 * Gets an unmodifiable view of the system properties saved at system 224 * initialization time. This method should only be used 225 * for the system properties that are not changed during runtime. 226 * 227 * Note that the saved system properties do not include 228 * the ones set by java.lang.VersionProps.init(). 229 */ 230 public static Map<String, String> getSavedProperties() { 231 if (savedProps == null) 232 throw new IllegalStateException("Not yet initialized"); 233 234 return Collections.unmodifiableMap(savedProps); 235 } 236 237 private static Map<String, String> savedProps; 238 239 // Save a private copy of the system properties and remove 240 // the system properties that are not intended for public access. 241 // 242 // This method can only be invoked during system initialization. 243 public static void saveProperties(Map<String, String> props) { 244 if (initLevel() != 0) 245 throw new IllegalStateException("Wrong init level"); 246 247 // only main thread is running at this time, so savedProps and 248 // its content will be correctly published to threads started later 249 if (savedProps == null) { 250 savedProps = props; 251 } 252 253 // Set the maximum amount of direct memory. This value is controlled 254 // by the vm option -XX:MaxDirectMemorySize=<size>. 255 // The maximum amount of allocatable direct buffer memory (in bytes) 256 // from the system property sun.nio.MaxDirectMemorySize set by the VM. 257 // If not set or set to -1, the max memory will be used 258 // The system property will be removed. 259 String s = props.get("sun.nio.MaxDirectMemorySize"); 260 if (s == null || s.isEmpty() || s.equals("-1")) { 261 // -XX:MaxDirectMemorySize not given, take default 262 directMemory = Runtime.getRuntime().maxMemory(); 263 } else { 264 long l = Long.parseLong(s); 265 if (l > -1) 266 directMemory = l; 267 } 268 269 // Check if direct buffers should be page aligned 270 s = props.get("sun.nio.PageAlignDirectMemory"); 271 if ("true".equals(s)) 272 pageAlignDirectMemory = true; 273 274 s = props.get("java.class.version"); 275 int index = s.indexOf('.'); 276 try { 277 classFileMajorVersion = Integer.parseInt(s.substring(0, index)); 278 classFileMinorVersion = Integer.parseInt(s.substring(index + 1)); 279 } catch (NumberFormatException e) { 280 throw new InternalError(e); 281 } 282 } 283 284 // Initialize any miscellaneous operating system settings that need to be 285 // set for the class libraries. 286 // 287 public static void initializeOSEnvironment() { 288 if (initLevel() == 0) { 289 OSEnvironment.initialize(); 290 } 291 } 292 293 /* Current count of objects pending for finalization */ 294 private static volatile int finalRefCount; 295 296 /* Peak count of objects pending for finalization */ 297 private static volatile int peakFinalRefCount; 298 299 /* 300 * Gets the number of objects pending for finalization. 301 * 302 * @return the number of objects pending for finalization. 303 */ 304 public static int getFinalRefCount() { 305 return finalRefCount; 306 } 307 308 /* 309 * Gets the peak number of objects pending for finalization. 310 * 311 * @return the peak number of objects pending for finalization. 312 */ 313 public static int getPeakFinalRefCount() { 314 return peakFinalRefCount; 315 } 316 317 /* 318 * Add {@code n} to the objects pending for finalization count. 319 * 320 * @param n an integer value to be added to the objects pending 321 * for finalization count 322 */ 323 public static void addFinalRefCount(int n) { 324 // The caller must hold lock to synchronize the update. 325 326 finalRefCount += n; 327 if (finalRefCount > peakFinalRefCount) { 328 peakFinalRefCount = finalRefCount; 329 } 330 } 331 332 /** 333 * Returns Thread.State for the given threadStatus 334 */ 335 public static Thread.State toThreadState(int threadStatus) { 336 if ((threadStatus & JVMTI_THREAD_STATE_RUNNABLE) != 0) { 337 return RUNNABLE; 338 } else if ((threadStatus & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) != 0) { 339 return BLOCKED; 340 } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) != 0) { 341 return WAITING; 342 } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) != 0) { 343 return TIMED_WAITING; 344 } else if ((threadStatus & JVMTI_THREAD_STATE_TERMINATED) != 0) { 345 return TERMINATED; 346 } else if ((threadStatus & JVMTI_THREAD_STATE_ALIVE) == 0) { 347 return NEW; 348 } else { 349 return RUNNABLE; 350 } 351 } 352 353 /* The threadStatus field is set by the VM at state transition 354 * in the hotspot implementation. Its value is set according to 355 * the JVM TI specification GetThreadState function. 356 */ 357 private static final int JVMTI_THREAD_STATE_ALIVE = 0x0001; 358 private static final int JVMTI_THREAD_STATE_TERMINATED = 0x0002; 359 private static final int JVMTI_THREAD_STATE_RUNNABLE = 0x0004; 360 private static final int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400; 361 private static final int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010; 362 private static final int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; 363 364 /* 365 * Returns the first user-defined class loader up the execution stack, 366 * or the platform class loader if only code from the platform or 367 * bootstrap class loader is on the stack. 368 */ 369 public static ClassLoader latestUserDefinedLoader() { 370 ClassLoader loader = latestUserDefinedLoader0(); 371 return loader != null ? loader : ClassLoader.getPlatformClassLoader(); 372 } 373 374 /* 375 * Returns the first user-defined class loader up the execution stack, 376 * or null if only code from the platform or bootstrap class loader is 377 * on the stack. VM does not keep a reference of platform loader and so 378 * it returns null. 379 * 380 * This method should be replaced with StackWalker::walk and then we can 381 * remove the logic in the VM. 382 */ 383 private static native ClassLoader latestUserDefinedLoader0(); 384 385 /** 386 * Returns {@code true} if we are in a set UID program. 387 */ 388 public static boolean isSetUID() { 389 long uid = getuid(); 390 long euid = geteuid(); 391 long gid = getgid(); 392 long egid = getegid(); 393 return uid != euid || gid != egid; 394 } 395 396 /** 397 * Returns the real user ID of the calling process, 398 * or -1 if the value is not available. 399 */ 400 public static native long getuid(); 401 402 /** 403 * Returns the effective user ID of the calling process, 404 * or -1 if the value is not available. 405 */ 406 public static native long geteuid(); 407 408 /** 409 * Returns the real group ID of the calling process, 410 * or -1 if the value is not available. 411 */ 412 public static native long getgid(); 413 414 /** 415 * Returns the effective group ID of the calling process, 416 * or -1 if the value is not available. 417 */ 418 public static native long getegid(); 419 420 /** 421 * Get a nanosecond time stamp adjustment in the form of a single long. 422 * 423 * This value can be used to create an instant using 424 * {@link java.time.Instant#ofEpochSecond(long, long) 425 * java.time.Instant.ofEpochSecond(offsetInSeconds, 426 * getNanoTimeAdjustment(offsetInSeconds))}. 427 * <p> 428 * The value returned has the best resolution available to the JVM on 429 * the current system. 430 * This is usually down to microseconds - or tenth of microseconds - 431 * depending on the OS/Hardware and the JVM implementation. 432 * 433 * @param offsetInSeconds The offset in seconds from which the nanosecond 434 * time stamp should be computed. 435 * 436 * @apiNote The offset should be recent enough - so that 437 * {@code offsetInSeconds} is within {@code +/- 2^32} seconds of the 438 * current UTC time. If the offset is too far off, {@code -1} will be 439 * returned. As such, {@code -1} must not be considered as a valid 440 * nano time adjustment, but as an exception value indicating 441 * that an offset closer to the current time should be used. 442 * 443 * @return A nanosecond time stamp adjustment in the form of a single long. 444 * If the offset is too far off the current time, this method returns -1. 445 * In that case, the caller should call this method again, passing a 446 * more accurate offset. 447 */ 448 public static native long getNanoTimeAdjustment(long offsetInSeconds); 449 450 /** 451 * Returns the VM arguments for this runtime environment. 452 * 453 * @implNote 454 * The HotSpot JVM processes the input arguments from multiple sources 455 * in the following order: 456 * 1. JAVA_TOOL_OPTIONS environment variable 457 * 2. Options from JNI Invocation API 458 * 3. _JAVA_OPTIONS environment variable 459 * 460 * If VM options file is specified via -XX:VMOptionsFile, the vm options 461 * file is read and expanded in place of -XX:VMOptionFile option. 462 */ 463 public static native String[] getRuntimeArguments(); 464 465 static { 466 initialize(); 467 } 468 private static native void initialize(); 469 470 /** 471 * Provides access to information on buffer usage. 472 */ 473 public interface BufferPool { 474 String getName(); 475 long getCount(); 476 long getTotalCapacity(); 477 long getMemoryUsed(); 478 } 479 480 private static class BufferPoolsHolder { 481 static final List<BufferPool> BUFFER_POOLS; 482 483 static { 484 ArrayList<BufferPool> bufferPools = new ArrayList<>(3); 485 bufferPools.add(SharedSecrets.getJavaNioAccess().getDirectBufferPool()); 486 bufferPools.add(FileChannelImpl.getMappedBufferPool()); 487 bufferPools.add(FileChannelImpl.getSyncMappedBufferPool()); 488 489 BUFFER_POOLS = Collections.unmodifiableList(bufferPools); 490 } 491 } 492 493 /** 494 * @return the list of buffer pools. 495 */ 496 public static List<BufferPool> getBufferPools() { 497 return BufferPoolsHolder.BUFFER_POOLS; 498 } 499 }