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 is not enabled")
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() && !mh->is_static() && !mh->is_object_initializer() && !mh->is_static_initializer()) {
90 ResourceMark rm;
91 int hot_count = 10; // TODO: what's the appropriate value?
92 CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, CompileTask::Reason_Bootstrap, CHECK);
93 }
94 }
95
96 int qsize;
97 bool first_round = true;
98 int z = 0;
99 do {
100 // Loop until there is something in the queue.
101 do {
102 THREAD->sleep(100);
103 qsize = CompileBroker::queue_size(CompLevel_full_optimization);
104 } while (!_bootstrap_compilation_request_handled && first_round && qsize == 0);
105 first_round = false;
106 if (PrintBootstrap) {
107 while (z < (_methods_compiled / 100)) {
108 ++z;
109 tty->print_raw(".");
110 }
111 }
112 } while (qsize != 0);
113
114 if (PrintBootstrap) {
115 tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)",
116 (jlong)nanos_to_millis(os::javaTimeNanos() - start), _methods_compiled);
117 }
118 _bootstrapping = false;
119 JVMCI::java_runtime()->bootstrap_finished(CHECK);
120 }
121
122 bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) {
123 if (_disabled) {
124 return true;
125 }
126 if (_bootstrapping) {
127 // When bootstrapping, the JVMCI compiler can compile its own methods.
128 return false;
129 }
130 if (UseJVMCINativeLibrary) {
131 // This mechanism exists to force compilation of a JVMCI compiler by C1
132 // to reduce the compilation time spent on the JVMCI compiler itself. In
133 // +UseJVMCINativeLibrary mode, the JVMCI compiler is AOT compiled.
134 return false;
135 } else {
136 JVMCIRuntime* runtime = JVMCI::java_runtime();
137 if (runtime != nullptr) {
138 JVMCIObject receiver = runtime->probe_HotSpotJVMCIRuntime();
139 if (receiver.is_null()) {
140 return false;
141 }
142 JVMCIEnv* ignored_env = nullptr;
143 objArrayHandle excludeModules(JavaThread::current(), HotSpotJVMCI::HotSpotJVMCIRuntime::excludeFromJVMCICompilation(ignored_env, HotSpotJVMCI::resolve(receiver)));
144 if (excludeModules.not_null()) {
145 ModuleEntry* moduleEntry = method->method_holder()->module();
146 for (int i = 0; i < excludeModules->length(); i++) {
147 if (excludeModules->obj_at(i) == moduleEntry->module()) {
148 return true;
149 }
150 }
151 }
152 }
153 return false;
154 }
155 }
156
157 // Compilation entry point for methods
158 void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, bool install_code, DirectiveSet* directive) {
159 ShouldNotReachHere();
160 }
161
162 void JVMCICompiler::stopping_compiler_thread(CompilerThread* current) {
163 if (UseJVMCINativeLibrary) {
164 JVMCIRuntime* runtime = JVMCI::compiler_runtime(current, false);
165 if (runtime != nullptr) {
166 MutexUnlocker unlock(CompileThread_lock);
167 runtime->detach_thread(current, "stopping idle compiler thread");
168 }
169 }
170 }
171
172 void JVMCICompiler::on_empty_queue(CompileQueue* queue, CompilerThread* thread) {
173 if (UseJVMCINativeLibrary) {
174 int delay = JVMCICompilerIdleDelay;
175 JVMCIRuntime* runtime = JVMCI::compiler_runtime(thread, false);
176 // Don't detach JVMCI compiler threads from their JVMCI
177 // runtime during the VM startup grace period
178 if (runtime != nullptr && delay > 0 && tty->time_stamp().milliseconds() > DEFAULT_COMPILER_IDLE_DELAY) {
179 bool timeout = MethodCompileQueue_lock->wait(delay);
180 // Unlock as detaching or repacking can result in a JNI call to shutdown a JavaVM
181 // and locks cannot be held when making a VM to native transition.
182 MutexUnlocker unlock(MethodCompileQueue_lock);
183 if (timeout) {
184 runtime->detach_thread(thread, "releasing idle compiler thread");
185 } else {
186 runtime->repack(thread);
187 }
188 }
189 }
190 }
191
192 // Print compilation timers
193 void JVMCICompiler::print_timers() {
194 tty->print_cr(" JVMCI CompileBroker Time:");
195 tty->print_cr(" Compile: %7.3f s", stats()->total_time());
196 _jit_code_installs.print_on(tty, " Install Code: ");
197 tty->cr();
198 tty->print_cr(" JVMCI Hosted Time:");
199 _hosted_code_installs.print_on(tty, " Install Code: ");
200 }
201
202 bool JVMCICompiler::is_intrinsic_supported(const methodHandle& method) {
203 vmIntrinsics::ID id = method->intrinsic_id();
204 assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
205 JavaThread* thread = JavaThread::current();
206 JVMCIEnv jvmciEnv(thread, __FILE__, __LINE__);
207 JVMCIRuntime* runtime = JVMCI::compiler_runtime(thread, false);
208 return runtime->is_intrinsic_supported(&jvmciEnv, (jint) id);
209 }
210
211 void JVMCICompiler::CodeInstallStats::print_on(outputStream* st, const char* prefix) const {
212 double time = _timer.seconds();
213 st->print_cr("%s%7.3f s (installs: %d, CodeBlob total size: %d, CodeBlob code size: %d)",
214 prefix, time, _count, _codeBlobs_size, _codeBlobs_code_size);
215 }
216
217 void JVMCICompiler::CodeInstallStats::on_install(CodeBlob* cb) {
218 Atomic::inc(&_count);
219 Atomic::add(&_codeBlobs_size, cb->size());
220 Atomic::add(&_codeBlobs_code_size, cb->code_size());
221 }
222
223 void JVMCICompiler::inc_methods_compiled() {
224 Atomic::inc(&_methods_compiled);
225 Atomic::inc(&_global_compilation_ticks);
226 }
227
228 void JVMCICompiler::on_upcall(const char* error, JVMCICompileState* compile_state) {
229 if (error != nullptr) {
230
231 Atomic::inc(&_err_upcalls);
232 int ok = _ok_upcalls;
233 int err = _err_upcalls;
234 // If there have been at least 10 upcalls with an error
235 // and the number of error upcalls is 10% or more of the
236 // number of non-error upcalls, disable JVMCI compilation.
237 if (err > 10 && err * 10 > ok && !_disabled) {
238 _disabled = true;
239 int total = err + ok;
240 // Using stringStream instead of err_msg to avoid truncation
241 stringStream st;
242 st.print("JVMCI compiler disabled "
243 "after %d of %d upcalls had errors (Last error: \"%s\"). "
244 "Use -Xlog:jit+compilation for more detail.", err, total, error);
245 const char* disable_msg = st.freeze();
246 log_warning(jit,compilation)("%s", disable_msg);
247 if (compile_state != nullptr) {
248 const char* disable_error = os::strdup(disable_msg);
249 if (disable_error != nullptr) {
250 compile_state->set_failure(true, disable_error, true);
251 JVMCI_event_1("%s", disable_error);
252 return;
253 } else {
254 // Leave failure reason as set by caller when strdup fails
255 }
256 }
257 }
258 JVMCI_event_1("JVMCI upcall had an error: %s", error);
259 } else {
260 Atomic::inc(&_ok_upcalls);
261 }
262 }
263
264 void JVMCICompiler::inc_global_compilation_ticks() {
265 Atomic::inc(&_global_compilation_ticks);
266 }
--- EOF ---