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