Path: blob/master/jcl/src/java.base/share/classes/java/lang/J9VMInternals.java
12513 views
/*[INCLUDE-IF JAVA_SPEC_VERSION >= 8]*/1/*******************************************************************************2* Copyright (c) 1998, 2022 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception21*******************************************************************************/22package java.lang;2324import com.ibm.oti.vm.J9UnmodifiableClass;25import java.lang.ref.SoftReference;26import java.lang.reflect.*;27import java.security.AccessController;28import java.security.PrivilegedAction;29import java.util.HashMap;30import java.util.Iterator;31import java.util.Map;32import java.util.Properties;33import java.util.WeakHashMap;34import java.security.AccessControlContext;35import java.security.CodeSource;36import java.security.ProtectionDomain;37import java.io.InputStream;38import java.io.OutputStream;39import java.io.PrintStream;40import java.net.URL;41/*[IF Sidecar19-SE]*/42import jdk.internal.ref.CleanerShutdown;43import jdk.internal.ref.CleanerImpl;44import jdk.internal.misc.Unsafe;45/*[ELSE]*/46import sun.misc.Unsafe;47/*[ENDIF]*/48import com.ibm.oti.util.Msg;4950@J9UnmodifiableClass51final class J9VMInternals {52/*[PR VMDESIGN 1891] Move j9Version and j9Config from Class to J9VMInternals */53/*[IF]*/54/**55* It is important that these remain static final56* because the VM peeks for them before running the <clinit>57*/58/*[ENDIF]*/59/*[IF]*/60// j9Version - 0xAABBCCCC61// AA - vm version, BB - jcl version, CCCC - master version62// Up the JCL version (BB) when adding functionality63/*[ENDIF]*/6465private static final int j9Version = 0x06040270;6667private static final long j9Config = 0x7363617237306200L; // 'scar70b\0'6869/*[REM] this field will be folded into methods compiled by the JIT and is needed for the fastIdentityHashCode optimization below */70/*[REM] the real value of this field is set in the System.afterClinitInitialization since this class starts too early */71/*[REM] do NOT set this field to null or javac can fold the null into fastIdentityHashCode and defeat the optimization */72static final com.ibm.jit.JITHelpers jitHelpers = com.ibm.jit.JITHelpers.getHelpers();7374// cannot create any instances in <clinit> in this special class75private static Map exceptions;7677static boolean initialized;78private static Unsafe unsafe;7980/* Ensure this class cannot be instantiated */81private J9VMInternals() {82}8384/*85* Called by the vm after everything else is initialized.86*/87private static void completeInitialization() {88initialized = true;89exceptions = new WeakHashMap();9091ClassLoader.completeInitialization();92Thread.currentThread().completeInitialization();9394/*[IF Sidecar19-SE]*/95System.initGPUAssist();9697if (Boolean.getBoolean("ibm.java9.forceCommonCleanerShutdown")) { //$NON-NLS-1$98Runnable runnable = () -> {99CleanerShutdown.shutdownCleaner();100ThreadGroup threadGroup = Thread.currentThread().group; // the system ThreadGroup101/*[IF OPENJDK_THREAD_SUPPORT]*/102ThreadGroup threadGroups[] = new ThreadGroup[threadGroup.ngroups];103/*[ELSE] OPENJDK_THREAD_SUPPORT104ThreadGroup threadGroups[] = new ThreadGroup[threadGroup.numGroups];105/*[ENDIF] OPENJDK_THREAD_SUPPORT */106threadGroup.enumerate(threadGroups, false); /* non-recursive enumeration */107for (ThreadGroup tg : threadGroups) {108if ("InnocuousThreadGroup".equals(tg.getName())) { //$NON-NLS-1$109/*[IF OPENJDK_THREAD_SUPPORT]*/110Thread threads[] = new Thread[tg.nthreads];111/*[ELSE] OPENJDK_THREAD_SUPPORT112Thread threads[] = new Thread[tg.numThreads];113/*[ENDIF] OPENJDK_THREAD_SUPPORT */114tg.enumerate(threads, false);115for (Thread t : threads) {116if (t.getName().equals("Common-Cleaner")) { //$NON-NLS-1$117t.interrupt();118try {119/* Need to wait for the Common-Cleaner thread to die before120* continuing. If not this will result in a race condition where121* the VM might attempt to shutdown before Common-Cleaner has a122* chance to stop properly. This will result in an unsuccessful123* shutdown and we will not release vm resources.124*/125t.join(3000);126/* giving this a 3sec timeout. If it works it should work fairly127* quickly, 3 seconds should be more than enough time. If it doesn't128* work it may block indefinitely. Turning on -verbose:shutdown will129* let us know if it worked or not130*/131} catch (Throwable e) {132/* empty block */133}134}135}136}137}138};139Runtime.getRuntime().addShutdownHook(new Thread(runnable, "CommonCleanerShutdown", true, false, false, null)); //$NON-NLS-1$140}141/*[ENDIF] Sidecar19-SE */142}143144/**145* Initialize a Class. See chapter146* 2.17.5 of the JVM Specification (2nd ed)147*/148static void initialize(Class<?> clazz) {149/* initializationLock == null means initialization successfully completed */150if (null != clazz.initializationLock) {151Unsafe localUnsafe = unsafe;152if (null == localUnsafe) {153localUnsafe = unsafe = Unsafe.getUnsafe();154}155localUnsafe.ensureClassInitialized(clazz);156}157}158159/**160* Throw a descriptive NoClassDefFoundError if an attempt is made161* to initialize a Class which has previously failed initialization.162*/163private static void initializationAlreadyFailed(Class clazz) {164/*[PR 118650] CLDC 1.1 includes java.lang.NoClassDefFoundError */165/*[PR 118653, CMVC 111503] Throw better NoClassDefFoundError for failed Class initialization */166NoClassDefFoundError notFound = new NoClassDefFoundError(clazz.getName() + " (initialization failure)"); //$NON-NLS-1$167// if exceptions is null, we're initializing and running single threaded168if (exceptions != null) {169synchronized(exceptions) {170/*[PR CMVC 195512] Throwable for class init error retained using WeakReference */171SoftReference weakReason = (SoftReference)exceptions.get(clazz);172if (weakReason != null) {173Throwable reason = (Throwable)weakReason.get();174if (reason != null) {175reason = copyThrowable(reason);176notFound.initCause(reason);177}178}179}180}181throw notFound;182}183184/**185* Record the cause (Throwable) of a failed initialization for a Class.186* If the Throwable is an Error, throw that, otherwise, wrap the Throwable187* in an ExceptionInInitializerError and throw that instead.188*/189private static void recordInitializationFailure(Class clazz, Throwable err) {190if (initialized) {191// if exceptions is null, we're initializing and running single threaded192if (exceptions == null)193exceptions = new WeakHashMap();194synchronized(exceptions) {195/*[IF JAVA_SPEC_VERSION >= 18]*/196if (!(err instanceof Error)) {197err = new ExceptionInInitializerError(err);198}199exceptions.put(clazz, new SoftReference(copyThrowable(err)));200/*[ELSE] JAVA_SPEC_VERSION >= 18*/201Throwable cause = err;202if (err instanceof ExceptionInInitializerError) {203cause = ((ExceptionInInitializerError)err).getException();204if (cause == null) {205/* Use the original ExceptionInInitializerError */206cause = err;207}208}209exceptions.put(clazz, new SoftReference(copyThrowable(cause)));210/*[ENDIF] JAVA_SPEC_VERSION >= 18*/211}212}213ensureError(err);214}215216/**217* If the incoming Throwable is an instance of Error, throw it.218* Otherwise, wrap it in a new ExceptionInInitializerError and throw that.219*/220private static void ensureError(Throwable err) {221if (err instanceof Error) {222throw (Error)err;223}224throw new ExceptionInInitializerError(err);225}226227private static native Throwable newInstance(Class exceptionClass, Class constructorClass);228229private static Throwable cloneThrowable(final Throwable throwable, final HashMap hashMapThrowable) {230return (Throwable)AccessController.doPrivileged(new PrivilegedAction() {231public Object run() {232Throwable clone;233try {234Class cls = throwable.getClass();235clone = newInstance(cls, Object.class);236while (cls != null) {237Field[] fields = cls.getDeclaredFields();238for (int i=0; i<fields.length; i++) {239if (!Modifier.isStatic(fields[i].getModifiers()) &&240!(cls == Throwable.class && fields[i].getName().equals("walkback"))) //$NON-NLS-1$241{242fields[i].setAccessible(true);243Object value;244if (cls == Throwable.class && fields[i].getName().equals("cause")) { //$NON-NLS-1$245value = clone;246} else {247value = fields[i].get(throwable);248// Only copy throwable fields whose stacktrace might be kept within Map exceptions249// The throwable stored within Map exceptions as WeakReference could be retrieved (before being GCed) later250if (value instanceof Throwable) {251value = copyThrowable((Throwable)value, hashMapThrowable);252}253}254fields[i].set(clone, value);255}256}257cls = getSuperclass(cls);258}259} catch (Throwable e) {260/*[MSG "K05c3", "Error cloning Throwable ({0}). The original exception was: {1}"]*/261clone = new Throwable(Msg.getString("K05c3", e, throwable.toString())); //$NON-NLS-1$262}263return clone;264}265});266}267268/**269* Entry method to copy the specified Throwable, invoke copyThrowable(Throwable, HashMap)270* to check loop such that we don't go infinite.271*272* @param throwable the Throwable to copy273*274* @return a copy of the Throwable275*/276private static Throwable copyThrowable(Throwable throwable) {277HashMap hashMapThrowable = new HashMap();278/*[PR CMVC 199629] Exception During Class Initialization Not Handled Correctly */279return copyThrowable(throwable, hashMapThrowable);280}281282/**283* Copy the specified Throwable, wrapping the stack trace for each284* Throwable. Check for loops so we don't go infinite.285*286* @param throwable the Throwable to copy287* @param hashMapThrowable the Throwables already cloned288*289* @return a copy of the Throwable or itself if it has been cloned already290*/291private static Throwable copyThrowable(Throwable throwable, HashMap hashMapThrowable) {292if (hashMapThrowable.get(throwable) != null) {293// stop recursive call here when the throwable has been cloned294return throwable;295}296hashMapThrowable.put(throwable, throwable);297Throwable root = cloneThrowable(throwable, hashMapThrowable);298root.setStackTrace(throwable.getStackTrace());299Throwable parent = root;300Throwable cause = throwable.getCause();301// looking for causes recursively which will be part of stacktrace stored into Map exceptions302while (cause != null && hashMapThrowable.get(cause) == null) {303hashMapThrowable.put(cause, cause);304Throwable child = cloneThrowable(cause, hashMapThrowable);305child.setStackTrace(cause.getStackTrace());306parent.setCause(child);307parent = child;308cause = cause.getCause();309}310return root;311}312313/**314* Private method to be called by the VM after a Threads dies and throws ThreadDeath315* It has to <code>notifyAll()</code> so that <code>join</code> can work properly.316* However, it has to be done when the Thread is "thought of" as being dead by other317* observer Threads (<code>isAlive()</code> has to return false for the Thread318* running this method or <code>join</code> may never return)319*320* @author OTI321* @version initial322*/323private static void threadCleanup(Thread thread) {324// don't synchronize the remove! Otherwise deadlock may occur325/*[PR 106323] -- remove might throw an exception, so make sure we finish the cleanup*/326try {327// Leave the ThreadGroup. This is why remove can't be private328/*[IF OPENJDK_THREAD_SUPPORT]*/329thread.group.threadTerminated(thread);330/*[ELSE] OPENJDK_THREAD_SUPPORT */331thread.group.remove(thread);332/*[ENDIF] OPENJDK_THREAD_SUPPORT */333} finally {334thread.cleanup();335336synchronized (thread) {337thread.notifyAll();338}339}340}341342/*[PR CVMC 124584] checkPackageAccess(), not defineClassImpl(), should use ProtectionDomain */343private static void checkPackageAccess(final Class clazz, ProtectionDomain pd) {344@SuppressWarnings("removal")345final SecurityManager sm = System.getSecurityManager();346if (sm != null) {347ProtectionDomain[] pdArray = (pd == null) ? new ProtectionDomain[]{} : new ProtectionDomain[]{pd};348AccessController.doPrivileged(new PrivilegedAction<Object>() {349@Override350public Object run() {351String packageName = clazz.getPackageName();352if (packageName != null) {353sm.checkPackageAccess(packageName);354}355if (Proxy.isProxyClass(clazz)) {356/*[PR CMVC 198986] Fix proxies */357ClassLoader cl = clazz.getClassLoaderImpl();358sun.reflect.misc.ReflectUtil.checkProxyPackageAccess(cl, clazz.getInterfaces());359}360return null;361}362}, new AccessControlContext(pdArray));363}364}365366/*[PR CMVC 104341] Exceptions in Object.finalize() not ignored */367368private static void runFinalize(Object obj) {369try {370obj.finalize();371} catch(Throwable e) {}372}373374static native StackTraceElement[] getStackTrace(Throwable throwable, boolean pruneConstructors);375376private static native void prepareClassImpl(Class clazz);377378/**379* Prepare the specified Class. Fill in initial field values, and send380* the class prepare event.381*382* @param clazz the Class to prepare383*/384static void prepare(Class clazz) {385if (clazz.initializationLock == null) {386/* initializationLock == null means initialization successfully completed */387return;388}389prepareClassImpl(clazz);390}391392/**393* Determines the superclass of specified <code>clazz</code>.394* @param clazz The class to introspect (must not be null).395* @return The superclass, or null for primitive types and interfaces.396*/397static native Class getSuperclass(Class clazz);398399/**400* Determines the interfaces implemented by <code>clazz</code>.401* @param clazz The class to introspect (must not be null).402* @return An array of all interfaces supported by <code>clazz</code>.403*/404static native Class[] getInterfaces(Class clazz);405406/**407* Answers a new instance of the class represented by the408* <code>clazz</code>, created by invoking the default (i.e. zero-argument)409* constructor. If there is no such constructor, or if the410* creation fails (either because of a lack of available memory or411* because an exception is thrown by the constructor), an412* InstantiationException is thrown. If the default constructor413* exists, but is not accessible from the context where this414* message is sent, an IllegalAccessException is thrown.415*416* @param clazz The class to create an instance of.417* @return a new instance of the class represented by the receiver.418* @throws IllegalAccessException if the constructor is not visible to the sender.419* @throws InstantiationException if the instance could not be created.420*/421native static Object newInstanceImpl(Class clazz)422throws IllegalAccessException, InstantiationException;423424/**425* Answers an integer hash code for the parameter.426* The hash code returned is the same one that would427* be returned by java.lang.Object.hashCode(), whether428* or not the object's class has overridden hashCode().429* Calling with null will cause a crash, so the caller430* must check for null. This version looks for a cached431* hash value using Java code to avoid calls to native432* code whenever possible and should be preferred to433* identityHashCode unless you know you don't want this434* optimization.435*436* @param anObject the object437* @return the hash code for the object438*439* @see java.lang.Object#hashCode440*/441static int fastIdentityHashCode(Object anObject) {442com.ibm.jit.JITHelpers h = jitHelpers;443if (null == h) {444return identityHashCode(anObject); /* use early returns to make the JIT code faster */445}446if (h.is32Bit()) {447int ptr = h.getIntFromObject(anObject, 0L);448if ((ptr & com.ibm.oti.vm.VM.OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS) != 0) {449if (!h.isArray(anObject)) {450int j9class = ptr & com.ibm.oti.vm.VM.J9_JAVA_CLASS_MASK;451return h.getIntFromObject(anObject, h.getBackfillOffsetFromJ9Class32(j9class));452}453}454} else {455long ptr = (com.ibm.oti.vm.VM.FJ9OBJECT_SIZE == 4) ? Integer.toUnsignedLong(h.getIntFromObject(anObject, 0L)) : h.getLongFromObject(anObject, 0L);456if ((ptr & com.ibm.oti.vm.VM.OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS) != 0) {457if (!h.isArray(anObject)) {458long j9class = ptr & com.ibm.oti.vm.VM.J9_JAVA_CLASS_MASK;459return h.getIntFromObject(anObject, h.getBackfillOffsetFromJ9Class64(j9class));460}461}462}463return identityHashCode(anObject);464}465466/**467* Answers an integer hash code for the parameter.468* The hash code returned is the same one that would469* be returned by java.lang.Object.hashCode(), whether470* or not the object's class has overridden hashCode().471* Calling with null will cause a crash, so the caller472* must check for null.473*474* @param anObject the object475* @return the hash code for the object476*477* @see java.lang.Object#hashCode478*/479static native int identityHashCode(Object anObject);480481/**482* Primitive implementation of Object.clone().483* Calling with null will cause a crash, so the caller484* must check for null.485*486* @param anObject the object487* @return a shallow copy of anObject488*489* @see java.lang.Object#clone490*/491static native Object primitiveClone(Object anObject) throws CloneNotSupportedException;492493/**494* A class used for synchronizing Class initialization.495*496* The instance field is currently only for debugging purposes.497*/498static final class ClassInitializationLock {499Class theClass;500}501502/**503* Native used to dump a string to the system console for debugging.504*505* @param str String506* the String to display507*/508public static native void dumpString(String str);509510511private static String[] getClassInfoStrings(final Class<?> clazz, String classPath){512String classLoaderStr = "<Bootstrap Loader>"; //$NON-NLS-1$513String cpResult = "<Unknown>"; //$NON-NLS-1$514515if (classPath == null) {516ClassLoader classLoader = clazz.getClassLoader();517if (classLoader != null) {518classLoaderStr = classLoader.toString();519classPath = AccessController.doPrivileged(new PrivilegedAction<String>() {520@Override521public String run() {522String path = null;523try {524ProtectionDomain pd = clazz.getProtectionDomain();525if (pd != null) {526CodeSource cs = pd.getCodeSource();527if (cs != null) {528URL loc = cs.getLocation();529if (loc != null) {530path = loc.toString();531}532}533}534} catch (Exception e) {535}536return path;537}538});539}540}541if (classPath != null) {542cpResult = classPath;543}544String [] strings = {cpResult, classLoaderStr};545return strings;546}547548/**549* Format a message to be used when creating a NoSuchMethodException from the VM.550* On failure returns methodSig ie the old style of NoSuchMethodException message551* @param methodSig String representation of the signature of the called method552* @param clazz1 The calling class,553* @param classPath1 Classpath used to load calling class. Only set when class is loaded by bootstrap loader554* @param clazz2 The called class.555* @param classPath2 Classpath used to load calling class. Only set when class is loaded by bootstrap loader556* @return the formatted message557*/558public static String formatNoSuchMethod(String methodSig, Class<?> clazz1, String classPath1, Class<?> clazz2, String classPath2) {559String[] callingClassInfo = null;560String[] calledClassInfo = null;561try{562callingClassInfo = getClassInfoStrings(clazz1, classPath1);563calledClassInfo = getClassInfoStrings(clazz2, classPath2);564565String[] args = {566methodSig, callingClassInfo[0], callingClassInfo[1],567clazz2.toString(), calledClassInfo[0], calledClassInfo[1]568};569570/*[MSG "K0613", "{0} (loaded from {1} by {2}) called from {3} (loaded from {4} by {5})."]*/571return com.ibm.oti.util.Msg.getString(572"K0613", //$NON-NLS-1$573"{0} (loaded from {1} by {2}) called from {3} (loaded from {4} by {5}).", //$NON-NLS-1$574args);575} catch (Exception | VirtualMachineError e) {576// don't catch ThreadDeath577if ((null == callingClassInfo) || (null == calledClassInfo)) {578return methodSig;579}580/* if retrieving the external message fails, hard code the message */581try {582return methodSig + "(loaded from " + callingClassInfo[0] + " by " + callingClassInfo[1] + ") called from " + clazz2.toString() +583" (loaded from " + calledClassInfo[0] + " by " + calledClassInfo[1] + ")";584} catch (Exception | VirtualMachineError e2) {585// don't catch ThreadDeath586/* if something fails, fall back to old message */587return methodSig;588}589}590591}592}593594595