Skip to content

Commit 398eb1e

Browse files
author
John Rose
committed
refactor jli init activity away from System; add JIT initialization indicator
1 parent 5056699 commit 398eb1e

File tree

7 files changed

+77
-19
lines changed

7 files changed

+77
-19
lines changed

src/hotspot/share/classfile/systemDictionary.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "classfile/systemDictionary.hpp"
4646
#include "classfile/vmClasses.hpp"
4747
#include "classfile/vmSymbols.hpp"
48+
#include "compiler/compileBroker.hpp"
4849
#include "gc/shared/gcTraceTime.inline.hpp"
4950
#include "interpreter/bootstrapInfo.hpp"
5051
#include "jfr/jfrEvents.hpp"
@@ -2035,6 +2036,11 @@ Method* SystemDictionary::find_method_handle_intrinsic(vmIntrinsicID iid,
20352036

20362037
// Throw OOM or the pending exception in the JavaThread
20372038
if (throw_error && !HAS_PENDING_EXCEPTION) {
2039+
if (!CompileBroker::is_initialized() && !Arguments::is_interpreter_only()) {
2040+
// Give a more accurate diagnostic; we didn't fill up the code cache:
2041+
THROW_MSG_NULL(vmSymbols::java_lang_InternalError(),
2042+
"Compile method handle intrinsic requested before compiler start-up");
2043+
}
20382044
THROW_MSG_NULL(vmSymbols::java_lang_OutOfMemoryError(),
20392045
"Out of space in CodeCache for method handle intrinsic");
20402046
}

src/hotspot/share/compiler/compileBroker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ void CompileBroker::compilation_init(JavaThread* THREAD) {
770770
CHECK);
771771
}
772772

773-
_initialized = true;
773+
Atomic::release_store(&_initialized, true);
774774
}
775775

776776
#if defined(ASSERT) && COMPILER2_OR_JVMCI
@@ -1329,7 +1329,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
13291329
CompileTask::CompileReason compile_reason,
13301330
TRAPS) {
13311331
// Do nothing if compilebroker is not initialized or compiles are submitted on level none
1332-
if (!_initialized || comp_level == CompLevel_none) {
1332+
if (!is_initialized() || comp_level == CompLevel_none) {
13331333
return nullptr;
13341334
}
13351335

src/hotspot/share/compiler/compileBroker.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ class CompileBroker: AllStatic {
288288
standard_entry_bci = InvocationEntryBci
289289
};
290290

291+
static bool is_initialized() {
292+
return Atomic::load_acquire(&_initialized);
293+
}
294+
291295
static AbstractCompiler* compiler(int comp_level) {
292296
if (is_c2_compile(comp_level)) return _compilers[1]; // C2
293297
if (is_c1_compile(comp_level)) return _compilers[0]; // C1

src/java.base/share/classes/java/lang/System.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.lang.annotation.Annotation;
3838
import java.lang.foreign.MemorySegment;
3939
import java.lang.invoke.MethodHandle;
40+
import java.lang.invoke.MethodHandles;
4041
import java.lang.invoke.MethodType;
4142
import java.lang.invoke.StringConcatFactory;
4243
import java.lang.module.ModuleDescriptor;
@@ -2228,21 +2229,15 @@ private static void initPhase1() {
22282229
// system properties, java.lang and other core classes are now initialized
22292230
VM.initLevel(VM.JAVA_LANG_SYSTEM_INITED);
22302231

2231-
try {
2232-
initJSR292Classes();
2233-
} catch (Throwable ex) {
2234-
throw new InternalError(ex);
2235-
}
2236-
VM.initLevel(VM.JAVA_LANG_INVOKE_INITED);
2232+
initJavaLangInvokeClasses();
22372233
}
22382234

22392235
// do phase1 initializations specific to JSR 292 APIs
2240-
private static void initJSR292Classes() throws Throwable {
2241-
var mh = java.lang.invoke.MethodHandles.identity(int.class);
2242-
int z = 0;
2243-
z |= (int) mh.invokeExact(z);
2244-
z |= (Integer) mh.invoke((Object)0);
2245-
if (z != 0) throw new AssertionError();
2236+
private static void initJavaLangInvokeClasses() {
2237+
// Merely touching MethodHandles is enough to warm up the
2238+
// java.lang.invoke subsystem.
2239+
MethodHandles.identity(int.class);
2240+
VM.initLevel(VM.JAVA_LANG_INVOKE_INITED);
22462241
}
22472242

22482243
/**

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8140,4 +8140,44 @@ public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHand
81408140
public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes) {
81418141
return VarHandles.dropCoordinates(target, pos, valueTypes);
81428142
}
8143+
8144+
// During VM bootstrap, java.lang.System (indirectly) calls this
8145+
// method in order to inititalize the java.lang.invoke subsystem.
8146+
private static void initializeViaSmokeTest() throws Throwable {
8147+
// First exercise the direct method handle infrastructure.
8148+
var MT_identity = MethodType.methodType(MethodHandle.class, Class.class);
8149+
var MH_identity = publicLookup().findStatic(MethodHandles.class, "identity", MT_identity);
8150+
// Get a MH from a combinator, two ways; make sure it is the same both ways.
8151+
var intid = (MethodHandle) MH_identity.invoke(int.class);
8152+
var mh = identity(int.class);
8153+
int z = 0; // should always be zero, badness detected if non-zero
8154+
if (intid != mh) z |= 1;
8155+
// Invoke the MH directly. Only zeroes should come out.
8156+
z |= (int) mh.invokeExact(z);
8157+
assert z == 0;
8158+
z |= (Integer) mh.invoke((Object)0);
8159+
assert z == 0;
8160+
z |= (int) new MutableCallSite(mh).dynamicInvoker().invoke(z);
8161+
assert z == 0;
8162+
// Run the MH through a call site, two ways.
8163+
intid = new ConstantCallSite(intid).dynamicInvoker();
8164+
if (intid != mh) z |= 2;
8165+
assert z == 0;
8166+
z |= (int) new MutableCallSite(mh).dynamicInvoker().invoke(z);
8167+
assert z == 0;
8168+
// Try out a VH
8169+
int[] a = { -1 };
8170+
var vh = arrayElementVarHandle(int[].class);
8171+
vh.set(a, 0, z);
8172+
z |= a[0];
8173+
assert z == 0;
8174+
// Mix a VH into a MH
8175+
z |= (int) vh.toMethodHandle(VarHandle.AccessMode.GET).bindTo(a).invokeExact(0);
8176+
// Z must still be zero.
8177+
if (z != 0) throw new AssertionError();
8178+
}
8179+
static {
8180+
try { initializeViaSmokeTest(); }
8181+
catch (Throwable ex) { throw new InternalError(ex); }
8182+
}
81438183
}

src/java.base/share/classes/jdk/internal/misc/CDS.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public class CDS {
4848
private static final int IS_USING_ARCHIVE = 1 << 3;
4949
private static final int configStatus = getCDSConfigStatus();
5050

51+
// TO DO: maybe hook something like this logic into AOT assembly shutdown:
52+
//private static void shutdownAOTAssembly() { configStatus = IS_USING_ARCHIVE; }
53+
5154
/**
5255
* Should we log the use of lambda form invokers?
5356
*/

src/java.base/share/classes/jdk/internal/misc/VM.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public class VM {
5959
private static volatile int initLevel;
6060
private static final @Stable boolean[] initLevelReached = new boolean[INIT_LEVEL_LIMIT];
6161
private static final Object lock = new Object();
62+
private static @Stable boolean isAOTCacheInited; // independent sub-state
6263

6364
/**
6465
* Sets the init level.
@@ -100,19 +101,28 @@ public static boolean initLevelReached(byte level) {
100101
return initLevelReached[level];
101102
}
102103

103-
private static @Stable boolean isAOTCacheInited;
104-
public static void setAOTCacheInited() {
104+
// TO DO: maybe hook something like this logic into AOT assembly shutdown:
105+
//private static void shutdownAOTAssembly() { setAOTCacheInited(); }
106+
static void setAOTCacheInited() {
105107
if (isAOTCacheInited) {
106108
throw new InternalError("AOT cache already inited");
107109
}
108-
isAOTCacheInited = true;
110+
isAOTCacheInited = CDS.isDumpingStaticArchive() ? false : true;
111+
// Note: this is not just another state such as
112+
// AOT_ASSEMBLY_DONE < VM_STARTED.
113+
//
114+
// That is because the AOT assembly phase runs up from
115+
// VM_STARTED through SYSTEM_BOOTED in order to synthesize an
116+
// AOT cache full of loaded classes and other goodies.
117+
// Thus, the true set of states is roughly the cross
118+
// product (initLevel, inassembly = !isAOTCacheInited).
109119
}
110120

111121
/**
112122
* Returns {@code true} if the AOT cache has been initialized.
113123
* This is almost always {@code true}, but may be false during a
114-
* special run of the VM called the "assembly phase", which
115-
* populates an AOT cache. If there was never an AOT cache for
124+
* special run of the VM called the "AOT assembly phase", which
125+
* populates an AOT cache. If there never was an AOT cache for
116126
* this run of the VM, the boolean is also {@code true}, as if
117127
* there was a very tiny AOT cache that was instantaneously
118128
* initialized.

0 commit comments

Comments
 (0)