1 /*
2 * Copyright (c) 2011, 2025, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include "classfile/moduleEntry.hpp"
25 #include "classfile/vmClasses.hpp"
26 #include "classfile/vmSymbols.hpp"
27 #include "compiler/compileBroker.hpp"
28 #include "compiler/compilerDefinitions.inline.hpp"
29 #include "jvmci/jvmciEnv.hpp"
30 #include "jvmci/jvmciRuntime.hpp"
31 #include "oops/objArrayOop.inline.hpp"
32 #include "runtime/arguments.hpp"
33 #include "runtime/handles.inline.hpp"
34
35 JVMCICompiler* JVMCICompiler::_instance = nullptr;
36
37 JVMCICompiler::JVMCICompiler() : AbstractCompiler(compiler_jvmci) {
38 _bootstrapping = false;
39 _bootstrap_compilation_request_handled = false;
40 _methods_compiled = 0;
41 _ok_upcalls = 0;
42 _err_upcalls = 0;
43 _disabled = false;
44 _global_compilation_ticks = 0;
45 assert(_instance == nullptr, "only one instance allowed");
46 _instance = this;
47 }
48
49 JVMCICompiler* JVMCICompiler::instance(bool require_non_null, TRAPS) {
50 if (!EnableJVMCI) {
51 THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), JVMCI_NOT_ENABLED_ERROR_MESSAGE)
52 }
53 if (_instance == nullptr && require_non_null) {
54 THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "The JVMCI compiler instance has not been created");
55 }
56 return _instance;
57 }
58
59 void compiler_stubs_init(bool in_compiler_thread);
60
61 // Initialization
62 void JVMCICompiler::initialize() {
63 assert(!CompilerConfig::is_c1_or_interpreter_only_no_jvmci(), "JVMCI is launched, it's not c1/interpreter only mode");
64 if (!UseCompiler || !EnableJVMCI || !UseJVMCICompiler || !should_perform_init()) {
65 return;
66 }
67 compiler_stubs_init(true /* in_compiler_thread */); // generate compiler's intrinsics stubs
68 set_state(initialized);
69 }
70
71 void JVMCICompiler::bootstrap(TRAPS) {
72 if (Arguments::mode() == Arguments::_int) {
73 // Nothing to do in -Xint mode
74 return;
75 }
76 _bootstrapping = true;
77 ResourceMark rm(THREAD);
78 HandleMark hm(THREAD);
79 if (PrintBootstrap) {
80 tty->print("Bootstrapping JVMCI");
81 }
82 jlong start = os::javaTimeNanos();
83
84 Array<Method*>* objectMethods = vmClasses::Object_klass()->methods();
85 // Initialize compile queue with a selected set of methods.
86 int len = objectMethods->length();
87 for (int i = 0; i < len; i++) {
88 methodHandle mh(THREAD, objectMethods->at(i));
89 if (!mh->is_native() &&
90 !mh->is_static() &&
91 !mh->is_object_constructor() &&
92 !mh->is_class_initializer()) {
93 ResourceMark rm;
94 int hot_count = 10; // TODO: what's the appropriate value?
95 CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, hot_count, CompileTask::Reason_Bootstrap, CHECK);
96 }
97 }
98
99 int qsize;
100 bool first_round = true;
101 int z = 0;
102 do {
103 // Loop until there is something in the queue.
104 do {
105 THREAD->sleep(100);
106 qsize = CompileBroker::queue_size(CompLevel_full_optimization);
107 } while (!_bootstrap_compilation_request_handled && first_round && qsize == 0);
108 first_round = false;
109 if (PrintBootstrap) {
110 while (z < (_methods_compiled / 100)) {
111 ++z;
112 tty->print_raw(".");
113 }
114 }
115 } while (qsize != 0);
116
117 if (PrintBootstrap) {
118 tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)",
119 (jlong)nanos_to_millis(os::javaTimeNanos() - start), _methods_compiled);
120 }
121 _bootstrapping = false;
122 JVMCI::java_runtime()->bootstrap_finished(CHECK);
123 }
124
125 bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) {
126 if (_disabled) {
127 return true;
128 }
129 if (_bootstrapping) {
130 // When bootstrapping, the JVMCI compiler can compile its own methods.
131 return false;
132 }
133 if (UseJVMCINativeLibrary) {
134 // This mechanism exists to force compilation of a JVMCI compiler by C1
135 // to reduce the compilation time spent on the JVMCI compiler itself. In
136 // +UseJVMCINativeLibrary mode, the JVMCI compiler is AOT compiled.
137 return false;
138 } else {
139 JVMCIRuntime* runtime = JVMCI::java_runtime();
140 if (runtime != nullptr) {
141 JVMCIObject receiver = runtime->probe_HotSpotJVMCIRuntime();
142 if (receiver.is_null()) {
143 return false;
144 }
145 JVMCIEnv* ignored_env = nullptr;
146 objArrayHandle excludeModules(JavaThread::current(), HotSpotJVMCI::HotSpotJVMCIRuntime::excludeFromJVMCICompilation(ignored_env, HotSpotJVMCI::resolve(receiver)));
147 if (excludeModules.not_null()) {
148 ModuleEntry* moduleEntry = method->method_holder()->module();
149 for (int i = 0; i < excludeModules->length(); i++) {
150 if (excludeModules->obj_at(i) == moduleEntry->module_oop()) {
151 return true;
152 }
153 }
154 }
155 }
156 return false;
157 }
158 }
159
160 // Compilation entry point for methods
161 void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, bool install_code, DirectiveSet* directive) {
162 ShouldNotReachHere();
163 }
164
165 void JVMCICompiler::stopping_compiler_thread(CompilerThread* current) {
166 if (UseJVMCINativeLibrary) {
167 JVMCIRuntime* runtime = JVMCI::compiler_runtime(current, false);
168 if (runtime != nullptr) {
169 MutexUnlocker unlock(CompileThread_lock);
170 runtime->detach_thread(current, "stopping idle compiler thread");
171 }
172 }
173 }
174
175 void JVMCICompiler::on_empty_queue(CompileQueue* queue, CompilerThread* thread) {
176 if (UseJVMCINativeLibrary) {
177 int delay = JVMCICompilerIdleDelay;
178 JVMCIRuntime* runtime = JVMCI::compiler_runtime(thread, false);
179 // Don't detach JVMCI compiler threads from their JVMCI
180 // runtime during the VM startup grace period
181 if (runtime != nullptr && delay > 0 && tty->time_stamp().milliseconds() > DEFAULT_COMPILER_IDLE_DELAY) {
182 bool timeout = MethodCompileQueue_lock->wait(delay);
183 // Unlock as detaching or repacking can result in a JNI call to shutdown a JavaVM
184 // and locks cannot be held when making a VM to native transition.
185 MutexUnlocker unlock(MethodCompileQueue_lock);
186 if (timeout) {
187 runtime->detach_thread(thread, "releasing idle compiler thread");
188 } else {
189 runtime->repack(thread);
190 }
191 }
192 }
193 }
194
195 // Print compilation timers
196 void JVMCICompiler::print_timers() {
197 tty->print_cr(" JVMCI CompileBroker Time:");
198 tty->print_cr(" Compile: %7.3f s", stats()->total_time());
199 _jit_code_installs.print_on(tty, " Install Code: ");
200 tty->cr();
201 tty->print_cr(" JVMCI Hosted Time:");
202 _hosted_code_installs.print_on(tty, " Install Code: ");
203 }
204
205 bool JVMCICompiler::is_intrinsic_supported(const methodHandle& method) {
206 vmIntrinsics::ID id = method->intrinsic_id();
207 assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
208 JavaThread* thread = JavaThread::current();
209 JVMCIEnv jvmciEnv(thread, __FILE__, __LINE__);
210 JVMCIRuntime* runtime = JVMCI::compiler_runtime(thread, false);
211 return runtime->is_intrinsic_supported(&jvmciEnv, (jint) id);
212 }
213
214 void JVMCICompiler::CodeInstallStats::print_on(outputStream* st, const char* prefix) const {
215 double time = _timer.seconds();
216 st->print_cr("%s%7.3f s (installs: %d, CodeBlob total size: %d, CodeBlob code size: %d)",
217 prefix, time, _count, _codeBlobs_size, _codeBlobs_code_size);
218 }
219
220 void JVMCICompiler::CodeInstallStats::on_install(CodeBlob* cb) {
221 AtomicAccess::inc(&_count);
222 AtomicAccess::add(&_codeBlobs_size, cb->size());
223 AtomicAccess::add(&_codeBlobs_code_size, cb->code_size());
224 }
225
226 void JVMCICompiler::inc_methods_compiled() {
227 AtomicAccess::inc(&_methods_compiled);
228 AtomicAccess::inc(&_global_compilation_ticks);
229 }
230
231 void JVMCICompiler::on_upcall(const char* error, JVMCICompileState* compile_state) {
232 if (error != nullptr) {
233
234 AtomicAccess::inc(&_err_upcalls);
235 int ok = _ok_upcalls;
236 int err = _err_upcalls;
237 // If there have been at least 10 upcalls with an error
238 // and the number of error upcalls is 10% or more of the
239 // number of non-error upcalls, disable JVMCI compilation.
240 if (err > 10 && err * 10 > ok && !_disabled) {
241 _disabled = true;
242 int total = err + ok;
243 // Using stringStream instead of err_msg to avoid truncation
244 stringStream st;
245 st.print("JVMCI compiler disabled "
246 "after %d of %d upcalls had errors (Last error: \"%s\"). "
247 "Use -Xlog:jit+compilation for more detail.", err, total, error);
248 const char* disable_msg = st.freeze();
249 log_warning(jit,compilation)("%s", disable_msg);
250 if (compile_state != nullptr) {
251 const char* disable_error = os::strdup(disable_msg);
252 if (disable_error != nullptr) {
253 compile_state->set_failure(true, disable_error, true);
254 JVMCI_event_1("%s", disable_error);
255 return;
256 } else {
257 // Leave failure reason as set by caller when strdup fails
258 }
259 }
260 }
261 JVMCI_event_1("JVMCI upcall had an error: %s", error);
262 } else {
263 AtomicAccess::inc(&_ok_upcalls);
264 }
265 }
266
267 void JVMCICompiler::inc_global_compilation_ticks() {
268 AtomicAccess::inc(&_global_compilation_ticks);
269 }