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