Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/jcl/src/java.base/share/classes/java/lang/J9VMInternals.java
12513 views
1
/*[INCLUDE-IF JAVA_SPEC_VERSION >= 8]*/
2
/*******************************************************************************
3
* Copyright (c) 1998, 2022 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* 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-exception
22
*******************************************************************************/
23
package java.lang;
24
25
import com.ibm.oti.vm.J9UnmodifiableClass;
26
import java.lang.ref.SoftReference;
27
import java.lang.reflect.*;
28
import java.security.AccessController;
29
import java.security.PrivilegedAction;
30
import java.util.HashMap;
31
import java.util.Iterator;
32
import java.util.Map;
33
import java.util.Properties;
34
import java.util.WeakHashMap;
35
import java.security.AccessControlContext;
36
import java.security.CodeSource;
37
import java.security.ProtectionDomain;
38
import java.io.InputStream;
39
import java.io.OutputStream;
40
import java.io.PrintStream;
41
import java.net.URL;
42
/*[IF Sidecar19-SE]*/
43
import jdk.internal.ref.CleanerShutdown;
44
import jdk.internal.ref.CleanerImpl;
45
import jdk.internal.misc.Unsafe;
46
/*[ELSE]*/
47
import sun.misc.Unsafe;
48
/*[ENDIF]*/
49
import com.ibm.oti.util.Msg;
50
51
@J9UnmodifiableClass
52
final class J9VMInternals {
53
/*[PR VMDESIGN 1891] Move j9Version and j9Config from Class to J9VMInternals */
54
/*[IF]*/
55
/**
56
* It is important that these remain static final
57
* because the VM peeks for them before running the <clinit>
58
*/
59
/*[ENDIF]*/
60
/*[IF]*/
61
// j9Version - 0xAABBCCCC
62
// AA - vm version, BB - jcl version, CCCC - master version
63
// Up the JCL version (BB) when adding functionality
64
/*[ENDIF]*/
65
66
private static final int j9Version = 0x06040270;
67
68
private static final long j9Config = 0x7363617237306200L; // 'scar70b\0'
69
70
/*[REM] this field will be folded into methods compiled by the JIT and is needed for the fastIdentityHashCode optimization below */
71
/*[REM] the real value of this field is set in the System.afterClinitInitialization since this class starts too early */
72
/*[REM] do NOT set this field to null or javac can fold the null into fastIdentityHashCode and defeat the optimization */
73
static final com.ibm.jit.JITHelpers jitHelpers = com.ibm.jit.JITHelpers.getHelpers();
74
75
// cannot create any instances in <clinit> in this special class
76
private static Map exceptions;
77
78
static boolean initialized;
79
private static Unsafe unsafe;
80
81
/* Ensure this class cannot be instantiated */
82
private J9VMInternals() {
83
}
84
85
/*
86
* Called by the vm after everything else is initialized.
87
*/
88
private static void completeInitialization() {
89
initialized = true;
90
exceptions = new WeakHashMap();
91
92
ClassLoader.completeInitialization();
93
Thread.currentThread().completeInitialization();
94
95
/*[IF Sidecar19-SE]*/
96
System.initGPUAssist();
97
98
if (Boolean.getBoolean("ibm.java9.forceCommonCleanerShutdown")) { //$NON-NLS-1$
99
Runnable runnable = () -> {
100
CleanerShutdown.shutdownCleaner();
101
ThreadGroup threadGroup = Thread.currentThread().group; // the system ThreadGroup
102
/*[IF OPENJDK_THREAD_SUPPORT]*/
103
ThreadGroup threadGroups[] = new ThreadGroup[threadGroup.ngroups];
104
/*[ELSE] OPENJDK_THREAD_SUPPORT
105
ThreadGroup threadGroups[] = new ThreadGroup[threadGroup.numGroups];
106
/*[ENDIF] OPENJDK_THREAD_SUPPORT */
107
threadGroup.enumerate(threadGroups, false); /* non-recursive enumeration */
108
for (ThreadGroup tg : threadGroups) {
109
if ("InnocuousThreadGroup".equals(tg.getName())) { //$NON-NLS-1$
110
/*[IF OPENJDK_THREAD_SUPPORT]*/
111
Thread threads[] = new Thread[tg.nthreads];
112
/*[ELSE] OPENJDK_THREAD_SUPPORT
113
Thread threads[] = new Thread[tg.numThreads];
114
/*[ENDIF] OPENJDK_THREAD_SUPPORT */
115
tg.enumerate(threads, false);
116
for (Thread t : threads) {
117
if (t.getName().equals("Common-Cleaner")) { //$NON-NLS-1$
118
t.interrupt();
119
try {
120
/* Need to wait for the Common-Cleaner thread to die before
121
* continuing. If not this will result in a race condition where
122
* the VM might attempt to shutdown before Common-Cleaner has a
123
* chance to stop properly. This will result in an unsuccessful
124
* shutdown and we will not release vm resources.
125
*/
126
t.join(3000);
127
/* giving this a 3sec timeout. If it works it should work fairly
128
* quickly, 3 seconds should be more than enough time. If it doesn't
129
* work it may block indefinitely. Turning on -verbose:shutdown will
130
* let us know if it worked or not
131
*/
132
} catch (Throwable e) {
133
/* empty block */
134
}
135
}
136
}
137
}
138
}
139
};
140
Runtime.getRuntime().addShutdownHook(new Thread(runnable, "CommonCleanerShutdown", true, false, false, null)); //$NON-NLS-1$
141
}
142
/*[ENDIF] Sidecar19-SE */
143
}
144
145
/**
146
* Initialize a Class. See chapter
147
* 2.17.5 of the JVM Specification (2nd ed)
148
*/
149
static void initialize(Class<?> clazz) {
150
/* initializationLock == null means initialization successfully completed */
151
if (null != clazz.initializationLock) {
152
Unsafe localUnsafe = unsafe;
153
if (null == localUnsafe) {
154
localUnsafe = unsafe = Unsafe.getUnsafe();
155
}
156
localUnsafe.ensureClassInitialized(clazz);
157
}
158
}
159
160
/**
161
* Throw a descriptive NoClassDefFoundError if an attempt is made
162
* to initialize a Class which has previously failed initialization.
163
*/
164
private static void initializationAlreadyFailed(Class clazz) {
165
/*[PR 118650] CLDC 1.1 includes java.lang.NoClassDefFoundError */
166
/*[PR 118653, CMVC 111503] Throw better NoClassDefFoundError for failed Class initialization */
167
NoClassDefFoundError notFound = new NoClassDefFoundError(clazz.getName() + " (initialization failure)"); //$NON-NLS-1$
168
// if exceptions is null, we're initializing and running single threaded
169
if (exceptions != null) {
170
synchronized(exceptions) {
171
/*[PR CMVC 195512] Throwable for class init error retained using WeakReference */
172
SoftReference weakReason = (SoftReference)exceptions.get(clazz);
173
if (weakReason != null) {
174
Throwable reason = (Throwable)weakReason.get();
175
if (reason != null) {
176
reason = copyThrowable(reason);
177
notFound.initCause(reason);
178
}
179
}
180
}
181
}
182
throw notFound;
183
}
184
185
/**
186
* Record the cause (Throwable) of a failed initialization for a Class.
187
* If the Throwable is an Error, throw that, otherwise, wrap the Throwable
188
* in an ExceptionInInitializerError and throw that instead.
189
*/
190
private static void recordInitializationFailure(Class clazz, Throwable err) {
191
if (initialized) {
192
// if exceptions is null, we're initializing and running single threaded
193
if (exceptions == null)
194
exceptions = new WeakHashMap();
195
synchronized(exceptions) {
196
/*[IF JAVA_SPEC_VERSION >= 18]*/
197
if (!(err instanceof Error)) {
198
err = new ExceptionInInitializerError(err);
199
}
200
exceptions.put(clazz, new SoftReference(copyThrowable(err)));
201
/*[ELSE] JAVA_SPEC_VERSION >= 18*/
202
Throwable cause = err;
203
if (err instanceof ExceptionInInitializerError) {
204
cause = ((ExceptionInInitializerError)err).getException();
205
if (cause == null) {
206
/* Use the original ExceptionInInitializerError */
207
cause = err;
208
}
209
}
210
exceptions.put(clazz, new SoftReference(copyThrowable(cause)));
211
/*[ENDIF] JAVA_SPEC_VERSION >= 18*/
212
}
213
}
214
ensureError(err);
215
}
216
217
/**
218
* If the incoming Throwable is an instance of Error, throw it.
219
* Otherwise, wrap it in a new ExceptionInInitializerError and throw that.
220
*/
221
private static void ensureError(Throwable err) {
222
if (err instanceof Error) {
223
throw (Error)err;
224
}
225
throw new ExceptionInInitializerError(err);
226
}
227
228
private static native Throwable newInstance(Class exceptionClass, Class constructorClass);
229
230
private static Throwable cloneThrowable(final Throwable throwable, final HashMap hashMapThrowable) {
231
return (Throwable)AccessController.doPrivileged(new PrivilegedAction() {
232
public Object run() {
233
Throwable clone;
234
try {
235
Class cls = throwable.getClass();
236
clone = newInstance(cls, Object.class);
237
while (cls != null) {
238
Field[] fields = cls.getDeclaredFields();
239
for (int i=0; i<fields.length; i++) {
240
if (!Modifier.isStatic(fields[i].getModifiers()) &&
241
!(cls == Throwable.class && fields[i].getName().equals("walkback"))) //$NON-NLS-1$
242
{
243
fields[i].setAccessible(true);
244
Object value;
245
if (cls == Throwable.class && fields[i].getName().equals("cause")) { //$NON-NLS-1$
246
value = clone;
247
} else {
248
value = fields[i].get(throwable);
249
// Only copy throwable fields whose stacktrace might be kept within Map exceptions
250
// The throwable stored within Map exceptions as WeakReference could be retrieved (before being GCed) later
251
if (value instanceof Throwable) {
252
value = copyThrowable((Throwable)value, hashMapThrowable);
253
}
254
}
255
fields[i].set(clone, value);
256
}
257
}
258
cls = getSuperclass(cls);
259
}
260
} catch (Throwable e) {
261
/*[MSG "K05c3", "Error cloning Throwable ({0}). The original exception was: {1}"]*/
262
clone = new Throwable(Msg.getString("K05c3", e, throwable.toString())); //$NON-NLS-1$
263
}
264
return clone;
265
}
266
});
267
}
268
269
/**
270
* Entry method to copy the specified Throwable, invoke copyThrowable(Throwable, HashMap)
271
* to check loop such that we don't go infinite.
272
*
273
* @param throwable the Throwable to copy
274
*
275
* @return a copy of the Throwable
276
*/
277
private static Throwable copyThrowable(Throwable throwable) {
278
HashMap hashMapThrowable = new HashMap();
279
/*[PR CMVC 199629] Exception During Class Initialization Not Handled Correctly */
280
return copyThrowable(throwable, hashMapThrowable);
281
}
282
283
/**
284
* Copy the specified Throwable, wrapping the stack trace for each
285
* Throwable. Check for loops so we don't go infinite.
286
*
287
* @param throwable the Throwable to copy
288
* @param hashMapThrowable the Throwables already cloned
289
*
290
* @return a copy of the Throwable or itself if it has been cloned already
291
*/
292
private static Throwable copyThrowable(Throwable throwable, HashMap hashMapThrowable) {
293
if (hashMapThrowable.get(throwable) != null) {
294
// stop recursive call here when the throwable has been cloned
295
return throwable;
296
}
297
hashMapThrowable.put(throwable, throwable);
298
Throwable root = cloneThrowable(throwable, hashMapThrowable);
299
root.setStackTrace(throwable.getStackTrace());
300
Throwable parent = root;
301
Throwable cause = throwable.getCause();
302
// looking for causes recursively which will be part of stacktrace stored into Map exceptions
303
while (cause != null && hashMapThrowable.get(cause) == null) {
304
hashMapThrowable.put(cause, cause);
305
Throwable child = cloneThrowable(cause, hashMapThrowable);
306
child.setStackTrace(cause.getStackTrace());
307
parent.setCause(child);
308
parent = child;
309
cause = cause.getCause();
310
}
311
return root;
312
}
313
314
/**
315
* Private method to be called by the VM after a Threads dies and throws ThreadDeath
316
* It has to <code>notifyAll()</code> so that <code>join</code> can work properly.
317
* However, it has to be done when the Thread is "thought of" as being dead by other
318
* observer Threads (<code>isAlive()</code> has to return false for the Thread
319
* running this method or <code>join</code> may never return)
320
*
321
* @author OTI
322
* @version initial
323
*/
324
private static void threadCleanup(Thread thread) {
325
// don't synchronize the remove! Otherwise deadlock may occur
326
/*[PR 106323] -- remove might throw an exception, so make sure we finish the cleanup*/
327
try {
328
// Leave the ThreadGroup. This is why remove can't be private
329
/*[IF OPENJDK_THREAD_SUPPORT]*/
330
thread.group.threadTerminated(thread);
331
/*[ELSE] OPENJDK_THREAD_SUPPORT */
332
thread.group.remove(thread);
333
/*[ENDIF] OPENJDK_THREAD_SUPPORT */
334
} finally {
335
thread.cleanup();
336
337
synchronized (thread) {
338
thread.notifyAll();
339
}
340
}
341
}
342
343
/*[PR CVMC 124584] checkPackageAccess(), not defineClassImpl(), should use ProtectionDomain */
344
private static void checkPackageAccess(final Class clazz, ProtectionDomain pd) {
345
@SuppressWarnings("removal")
346
final SecurityManager sm = System.getSecurityManager();
347
if (sm != null) {
348
ProtectionDomain[] pdArray = (pd == null) ? new ProtectionDomain[]{} : new ProtectionDomain[]{pd};
349
AccessController.doPrivileged(new PrivilegedAction<Object>() {
350
@Override
351
public Object run() {
352
String packageName = clazz.getPackageName();
353
if (packageName != null) {
354
sm.checkPackageAccess(packageName);
355
}
356
if (Proxy.isProxyClass(clazz)) {
357
/*[PR CMVC 198986] Fix proxies */
358
ClassLoader cl = clazz.getClassLoaderImpl();
359
sun.reflect.misc.ReflectUtil.checkProxyPackageAccess(cl, clazz.getInterfaces());
360
}
361
return null;
362
}
363
}, new AccessControlContext(pdArray));
364
}
365
}
366
367
/*[PR CMVC 104341] Exceptions in Object.finalize() not ignored */
368
369
private static void runFinalize(Object obj) {
370
try {
371
obj.finalize();
372
} catch(Throwable e) {}
373
}
374
375
static native StackTraceElement[] getStackTrace(Throwable throwable, boolean pruneConstructors);
376
377
private static native void prepareClassImpl(Class clazz);
378
379
/**
380
* Prepare the specified Class. Fill in initial field values, and send
381
* the class prepare event.
382
*
383
* @param clazz the Class to prepare
384
*/
385
static void prepare(Class clazz) {
386
if (clazz.initializationLock == null) {
387
/* initializationLock == null means initialization successfully completed */
388
return;
389
}
390
prepareClassImpl(clazz);
391
}
392
393
/**
394
* Determines the superclass of specified <code>clazz</code>.
395
* @param clazz The class to introspect (must not be null).
396
* @return The superclass, or null for primitive types and interfaces.
397
*/
398
static native Class getSuperclass(Class clazz);
399
400
/**
401
* Determines the interfaces implemented by <code>clazz</code>.
402
* @param clazz The class to introspect (must not be null).
403
* @return An array of all interfaces supported by <code>clazz</code>.
404
*/
405
static native Class[] getInterfaces(Class clazz);
406
407
/**
408
* Answers a new instance of the class represented by the
409
* <code>clazz</code>, created by invoking the default (i.e. zero-argument)
410
* constructor. If there is no such constructor, or if the
411
* creation fails (either because of a lack of available memory or
412
* because an exception is thrown by the constructor), an
413
* InstantiationException is thrown. If the default constructor
414
* exists, but is not accessible from the context where this
415
* message is sent, an IllegalAccessException is thrown.
416
*
417
* @param clazz The class to create an instance of.
418
* @return a new instance of the class represented by the receiver.
419
* @throws IllegalAccessException if the constructor is not visible to the sender.
420
* @throws InstantiationException if the instance could not be created.
421
*/
422
native static Object newInstanceImpl(Class clazz)
423
throws IllegalAccessException, InstantiationException;
424
425
/**
426
* Answers an integer hash code for the parameter.
427
* The hash code returned is the same one that would
428
* be returned by java.lang.Object.hashCode(), whether
429
* or not the object's class has overridden hashCode().
430
* Calling with null will cause a crash, so the caller
431
* must check for null. This version looks for a cached
432
* hash value using Java code to avoid calls to native
433
* code whenever possible and should be preferred to
434
* identityHashCode unless you know you don't want this
435
* optimization.
436
*
437
* @param anObject the object
438
* @return the hash code for the object
439
*
440
* @see java.lang.Object#hashCode
441
*/
442
static int fastIdentityHashCode(Object anObject) {
443
com.ibm.jit.JITHelpers h = jitHelpers;
444
if (null == h) {
445
return identityHashCode(anObject); /* use early returns to make the JIT code faster */
446
}
447
if (h.is32Bit()) {
448
int ptr = h.getIntFromObject(anObject, 0L);
449
if ((ptr & com.ibm.oti.vm.VM.OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS) != 0) {
450
if (!h.isArray(anObject)) {
451
int j9class = ptr & com.ibm.oti.vm.VM.J9_JAVA_CLASS_MASK;
452
return h.getIntFromObject(anObject, h.getBackfillOffsetFromJ9Class32(j9class));
453
}
454
}
455
} else {
456
long ptr = (com.ibm.oti.vm.VM.FJ9OBJECT_SIZE == 4) ? Integer.toUnsignedLong(h.getIntFromObject(anObject, 0L)) : h.getLongFromObject(anObject, 0L);
457
if ((ptr & com.ibm.oti.vm.VM.OBJECT_HEADER_HAS_BEEN_MOVED_IN_CLASS) != 0) {
458
if (!h.isArray(anObject)) {
459
long j9class = ptr & com.ibm.oti.vm.VM.J9_JAVA_CLASS_MASK;
460
return h.getIntFromObject(anObject, h.getBackfillOffsetFromJ9Class64(j9class));
461
}
462
}
463
}
464
return identityHashCode(anObject);
465
}
466
467
/**
468
* Answers an integer hash code for the parameter.
469
* The hash code returned is the same one that would
470
* be returned by java.lang.Object.hashCode(), whether
471
* or not the object's class has overridden hashCode().
472
* Calling with null will cause a crash, so the caller
473
* must check for null.
474
*
475
* @param anObject the object
476
* @return the hash code for the object
477
*
478
* @see java.lang.Object#hashCode
479
*/
480
static native int identityHashCode(Object anObject);
481
482
/**
483
* Primitive implementation of Object.clone().
484
* Calling with null will cause a crash, so the caller
485
* must check for null.
486
*
487
* @param anObject the object
488
* @return a shallow copy of anObject
489
*
490
* @see java.lang.Object#clone
491
*/
492
static native Object primitiveClone(Object anObject) throws CloneNotSupportedException;
493
494
/**
495
* A class used for synchronizing Class initialization.
496
*
497
* The instance field is currently only for debugging purposes.
498
*/
499
static final class ClassInitializationLock {
500
Class theClass;
501
}
502
503
/**
504
* Native used to dump a string to the system console for debugging.
505
*
506
* @param str String
507
* the String to display
508
*/
509
public static native void dumpString(String str);
510
511
512
private static String[] getClassInfoStrings(final Class<?> clazz, String classPath){
513
String classLoaderStr = "<Bootstrap Loader>"; //$NON-NLS-1$
514
String cpResult = "<Unknown>"; //$NON-NLS-1$
515
516
if (classPath == null) {
517
ClassLoader classLoader = clazz.getClassLoader();
518
if (classLoader != null) {
519
classLoaderStr = classLoader.toString();
520
classPath = AccessController.doPrivileged(new PrivilegedAction<String>() {
521
@Override
522
public String run() {
523
String path = null;
524
try {
525
ProtectionDomain pd = clazz.getProtectionDomain();
526
if (pd != null) {
527
CodeSource cs = pd.getCodeSource();
528
if (cs != null) {
529
URL loc = cs.getLocation();
530
if (loc != null) {
531
path = loc.toString();
532
}
533
}
534
}
535
} catch (Exception e) {
536
}
537
return path;
538
}
539
});
540
}
541
}
542
if (classPath != null) {
543
cpResult = classPath;
544
}
545
String [] strings = {cpResult, classLoaderStr};
546
return strings;
547
}
548
549
/**
550
* Format a message to be used when creating a NoSuchMethodException from the VM.
551
* On failure returns methodSig ie the old style of NoSuchMethodException message
552
* @param methodSig String representation of the signature of the called method
553
* @param clazz1 The calling class,
554
* @param classPath1 Classpath used to load calling class. Only set when class is loaded by bootstrap loader
555
* @param clazz2 The called class.
556
* @param classPath2 Classpath used to load calling class. Only set when class is loaded by bootstrap loader
557
* @return the formatted message
558
*/
559
public static String formatNoSuchMethod(String methodSig, Class<?> clazz1, String classPath1, Class<?> clazz2, String classPath2) {
560
String[] callingClassInfo = null;
561
String[] calledClassInfo = null;
562
try{
563
callingClassInfo = getClassInfoStrings(clazz1, classPath1);
564
calledClassInfo = getClassInfoStrings(clazz2, classPath2);
565
566
String[] args = {
567
methodSig, callingClassInfo[0], callingClassInfo[1],
568
clazz2.toString(), calledClassInfo[0], calledClassInfo[1]
569
};
570
571
/*[MSG "K0613", "{0} (loaded from {1} by {2}) called from {3} (loaded from {4} by {5})."]*/
572
return com.ibm.oti.util.Msg.getString(
573
"K0613", //$NON-NLS-1$
574
"{0} (loaded from {1} by {2}) called from {3} (loaded from {4} by {5}).", //$NON-NLS-1$
575
args);
576
} catch (Exception | VirtualMachineError e) {
577
// don't catch ThreadDeath
578
if ((null == callingClassInfo) || (null == calledClassInfo)) {
579
return methodSig;
580
}
581
/* if retrieving the external message fails, hard code the message */
582
try {
583
return methodSig + "(loaded from " + callingClassInfo[0] + " by " + callingClassInfo[1] + ") called from " + clazz2.toString() +
584
" (loaded from " + calledClassInfo[0] + " by " + calledClassInfo[1] + ")";
585
} catch (Exception | VirtualMachineError e2) {
586
// don't catch ThreadDeath
587
/* if something fails, fall back to old message */
588
return methodSig;
589
}
590
}
591
592
}
593
}
594
595