1 | /* |
2 | * Copyright (c) 1998, 2019, 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 | |
25 | #include "precompiled.hpp" |
26 | #include "compiler/compileTask.hpp" |
27 | #include "compiler/compileLog.hpp" |
28 | #include "compiler/compileBroker.hpp" |
29 | #include "compiler/compilerDirectives.hpp" |
30 | #include "logging/log.hpp" |
31 | #include "logging/logStream.hpp" |
32 | #include "memory/resourceArea.hpp" |
33 | #include "runtime/handles.inline.hpp" |
34 | |
35 | CompileTask* CompileTask::_task_free_list = NULL; |
36 | #ifdef ASSERT |
37 | int CompileTask::_num_allocated_tasks = 0; |
38 | #endif |
39 | |
40 | /** |
41 | * Allocate a CompileTask, from the free list if possible. |
42 | */ |
43 | CompileTask* CompileTask::allocate() { |
44 | MutexLocker locker(CompileTaskAlloc_lock); |
45 | CompileTask* task = NULL; |
46 | |
47 | if (_task_free_list != NULL) { |
48 | task = _task_free_list; |
49 | _task_free_list = task->next(); |
50 | task->set_next(NULL); |
51 | } else { |
52 | task = new CompileTask(); |
53 | DEBUG_ONLY(_num_allocated_tasks++;) |
54 | assert (WhiteBoxAPI || JVMCI_ONLY(UseJVMCICompiler ||) _num_allocated_tasks < 10000, "Leaking compilation tasks?" ); |
55 | task->set_next(NULL); |
56 | task->set_is_free(true); |
57 | } |
58 | assert(task->is_free(), "Task must be free." ); |
59 | task->set_is_free(false); |
60 | return task; |
61 | } |
62 | |
63 | /** |
64 | * Add a task to the free list. |
65 | */ |
66 | void CompileTask::free(CompileTask* task) { |
67 | MutexLocker locker(CompileTaskAlloc_lock); |
68 | if (!task->is_free()) { |
69 | task->set_code(NULL); |
70 | assert(!task->lock()->is_locked(), "Should not be locked when freed" ); |
71 | if ((task->_method_holder != NULL && JNIHandles::is_weak_global_handle(task->_method_holder)) || |
72 | (task->_hot_method_holder != NULL && JNIHandles::is_weak_global_handle(task->_hot_method_holder))) { |
73 | JNIHandles::destroy_weak_global(task->_method_holder); |
74 | JNIHandles::destroy_weak_global(task->_hot_method_holder); |
75 | } else { |
76 | JNIHandles::destroy_global(task->_method_holder); |
77 | JNIHandles::destroy_global(task->_hot_method_holder); |
78 | } |
79 | if (task->_failure_reason_on_C_heap && task->_failure_reason != NULL) { |
80 | os::free((void*) task->_failure_reason); |
81 | } |
82 | task->_failure_reason = NULL; |
83 | task->_failure_reason_on_C_heap = false; |
84 | |
85 | task->set_is_free(true); |
86 | task->set_next(_task_free_list); |
87 | _task_free_list = task; |
88 | } |
89 | } |
90 | |
91 | void CompileTask::initialize(int compile_id, |
92 | const methodHandle& method, |
93 | int osr_bci, |
94 | int comp_level, |
95 | const methodHandle& hot_method, |
96 | int hot_count, |
97 | CompileTask::CompileReason compile_reason, |
98 | bool is_blocking) { |
99 | assert(!_lock->is_locked(), "bad locking" ); |
100 | |
101 | Thread* thread = Thread::current(); |
102 | _compile_id = compile_id; |
103 | _method = method(); |
104 | _method_holder = JNIHandles::make_weak_global(Handle(thread, method->method_holder()->klass_holder())); |
105 | _osr_bci = osr_bci; |
106 | _is_blocking = is_blocking; |
107 | JVMCI_ONLY(_has_waiter = CompileBroker::compiler(comp_level)->is_jvmci();) |
108 | JVMCI_ONLY(_jvmci_compiler_thread = NULL;) |
109 | _comp_level = comp_level; |
110 | _num_inlined_bytecodes = 0; |
111 | |
112 | _is_complete = false; |
113 | _is_success = false; |
114 | _code_handle = NULL; |
115 | |
116 | _hot_method = NULL; |
117 | _hot_method_holder = NULL; |
118 | _hot_count = hot_count; |
119 | _time_queued = os::elapsed_counter(); |
120 | _time_started = 0; |
121 | _compile_reason = compile_reason; |
122 | _failure_reason = NULL; |
123 | _failure_reason_on_C_heap = false; |
124 | |
125 | if (LogCompilation) { |
126 | if (hot_method.not_null()) { |
127 | if (hot_method == method) { |
128 | _hot_method = _method; |
129 | } else { |
130 | _hot_method = hot_method(); |
131 | // only add loader or mirror if different from _method_holder |
132 | _hot_method_holder = JNIHandles::make_weak_global(Handle(thread, hot_method->method_holder()->klass_holder())); |
133 | } |
134 | } |
135 | } |
136 | |
137 | _next = NULL; |
138 | } |
139 | |
140 | /** |
141 | * Returns the compiler for this task. |
142 | */ |
143 | AbstractCompiler* CompileTask::compiler() { |
144 | return CompileBroker::compiler(_comp_level); |
145 | } |
146 | |
147 | // Replace weak handles by strong handles to avoid unloading during compilation. |
148 | CompileTask* CompileTask::select_for_compilation() { |
149 | if (is_unloaded()) { |
150 | // Guard against concurrent class unloading |
151 | return NULL; |
152 | } |
153 | Thread* thread = Thread::current(); |
154 | assert(_method->method_holder()->is_loader_alive(), "should be alive" ); |
155 | Handle method_holder(thread, _method->method_holder()->klass_holder()); |
156 | JNIHandles::destroy_weak_global(_method_holder); |
157 | JNIHandles::destroy_weak_global(_hot_method_holder); |
158 | _method_holder = JNIHandles::make_global(method_holder); |
159 | if (_hot_method != NULL) { |
160 | _hot_method_holder = JNIHandles::make_global(Handle(thread, _hot_method->method_holder()->klass_holder())); |
161 | } |
162 | return this; |
163 | } |
164 | |
165 | // ------------------------------------------------------------------ |
166 | // CompileTask::code/set_code |
167 | // |
168 | nmethod* CompileTask::code() const { |
169 | if (_code_handle == NULL) return NULL; |
170 | CodeBlob *blob = _code_handle->code(); |
171 | if (blob != NULL) { |
172 | return blob->as_nmethod(); |
173 | } |
174 | return NULL; |
175 | } |
176 | |
177 | void CompileTask::set_code(nmethod* nm) { |
178 | if (_code_handle == NULL && nm == NULL) return; |
179 | guarantee(_code_handle != NULL, "" ); |
180 | _code_handle->set_code(nm); |
181 | if (nm == NULL) _code_handle = NULL; // drop the handle also |
182 | } |
183 | |
184 | void CompileTask::mark_on_stack() { |
185 | if (is_unloaded()) { |
186 | return; |
187 | } |
188 | // Mark these methods as something redefine classes cannot remove. |
189 | _method->set_on_stack(true); |
190 | if (_hot_method != NULL) { |
191 | _hot_method->set_on_stack(true); |
192 | } |
193 | } |
194 | |
195 | bool CompileTask::is_unloaded() const { |
196 | return _method_holder != NULL && JNIHandles::is_weak_global_handle(_method_holder) && JNIHandles::is_global_weak_cleared(_method_holder); |
197 | } |
198 | |
199 | // RedefineClasses support |
200 | void CompileTask::metadata_do(MetadataClosure* f) { |
201 | if (is_unloaded()) { |
202 | return; |
203 | } |
204 | f->do_metadata(method()); |
205 | if (hot_method() != NULL && hot_method() != method()) { |
206 | f->do_metadata(hot_method()); |
207 | } |
208 | } |
209 | |
210 | // ------------------------------------------------------------------ |
211 | // CompileTask::print_line_on_error |
212 | // |
213 | // This function is called by fatal error handler when the thread |
214 | // causing troubles is a compiler thread. |
215 | // |
216 | // Do not grab any lock, do not allocate memory. |
217 | // |
218 | // Otherwise it's the same as CompileTask::print_line() |
219 | // |
220 | void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) { |
221 | // print compiler name |
222 | st->print("%s:" , CompileBroker::compiler_name(comp_level())); |
223 | print(st); |
224 | } |
225 | |
226 | // ------------------------------------------------------------------ |
227 | // CompileTask::print_tty |
228 | void CompileTask::print_tty() { |
229 | ttyLocker ttyl; // keep the following output all in one block |
230 | // print compiler name if requested |
231 | if (CIPrintCompilerName) { |
232 | tty->print("%s:" , CompileBroker::compiler_name(comp_level())); |
233 | } |
234 | print(tty); |
235 | } |
236 | |
237 | // ------------------------------------------------------------------ |
238 | // CompileTask::print_impl |
239 | void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, int comp_level, |
240 | bool is_osr_method, int osr_bci, bool is_blocking, |
241 | const char* msg, bool short_form, bool cr, |
242 | jlong time_queued, jlong time_started) { |
243 | if (!short_form) { |
244 | // Print current time |
245 | st->print("%7d " , (int)st->time_stamp().milliseconds()); |
246 | if (Verbose && time_queued != 0) { |
247 | // Print time in queue and time being processed by compiler thread |
248 | jlong now = os::elapsed_counter(); |
249 | st->print("%d " , (int)TimeHelper::counter_to_millis(now-time_queued)); |
250 | if (time_started != 0) { |
251 | st->print("%d " , (int)TimeHelper::counter_to_millis(now-time_started)); |
252 | } |
253 | } |
254 | } |
255 | // print compiler name if requested |
256 | if (CIPrintCompilerName) { |
257 | st->print("%s:" , CompileBroker::compiler_name(comp_level)); |
258 | } |
259 | st->print("%4d " , compile_id); // print compilation number |
260 | |
261 | // For unloaded methods the transition to zombie occurs after the |
262 | // method is cleared so it's impossible to report accurate |
263 | // information for that case. |
264 | bool is_synchronized = false; |
265 | bool has_exception_handler = false; |
266 | bool is_native = false; |
267 | if (method != NULL) { |
268 | is_synchronized = method->is_synchronized(); |
269 | has_exception_handler = method->has_exception_handler(); |
270 | is_native = method->is_native(); |
271 | } |
272 | // method attributes |
273 | const char compile_type = is_osr_method ? '%' : ' '; |
274 | const char sync_char = is_synchronized ? 's' : ' '; |
275 | const char exception_char = has_exception_handler ? '!' : ' '; |
276 | const char blocking_char = is_blocking ? 'b' : ' '; |
277 | const char native_char = is_native ? 'n' : ' '; |
278 | |
279 | // print method attributes |
280 | st->print("%c%c%c%c%c " , compile_type, sync_char, exception_char, blocking_char, native_char); |
281 | |
282 | if (TieredCompilation) { |
283 | if (comp_level != -1) st->print("%d " , comp_level); |
284 | else st->print("- " ); |
285 | } |
286 | st->print(" " ); // more indent |
287 | |
288 | if (method == NULL) { |
289 | st->print("(method)" ); |
290 | } else { |
291 | method->print_short_name(st); |
292 | if (is_osr_method) { |
293 | st->print(" @ %d" , osr_bci); |
294 | } |
295 | if (method->is_native()) |
296 | st->print(" (native)" ); |
297 | else |
298 | st->print(" (%d bytes)" , method->code_size()); |
299 | } |
300 | |
301 | if (msg != NULL) { |
302 | st->print(" %s" , msg); |
303 | } |
304 | if (cr) { |
305 | st->cr(); |
306 | } |
307 | } |
308 | |
309 | void CompileTask::print_inline_indent(int inline_level, outputStream* st) { |
310 | // 1234567 |
311 | st->print(" " ); // print timestamp |
312 | // 1234 |
313 | st->print(" " ); // print compilation number |
314 | // %s!bn |
315 | st->print(" " ); // print method attributes |
316 | if (TieredCompilation) { |
317 | st->print(" " ); |
318 | } |
319 | st->print(" " ); // more indent |
320 | st->print(" " ); // initial inlining indent |
321 | for (int i = 0; i < inline_level; i++) st->print(" " ); |
322 | } |
323 | |
324 | // ------------------------------------------------------------------ |
325 | // CompileTask::print_compilation |
326 | void CompileTask::print(outputStream* st, const char* msg, bool short_form, bool cr) { |
327 | bool is_osr_method = osr_bci() != InvocationEntryBci; |
328 | print_impl(st, is_unloaded() ? NULL : method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form, cr, _time_queued, _time_started); |
329 | } |
330 | |
331 | // ------------------------------------------------------------------ |
332 | // CompileTask::log_task |
333 | void CompileTask::log_task(xmlStream* log) { |
334 | Thread* thread = Thread::current(); |
335 | methodHandle method(thread, this->method()); |
336 | ResourceMark rm(thread); |
337 | |
338 | // <task id='9' method='M' osr_bci='X' level='1' blocking='1' stamp='1.234'> |
339 | log->print(" compile_id='%d'" , _compile_id); |
340 | if (_osr_bci != CompileBroker::standard_entry_bci) { |
341 | log->print(" compile_kind='osr'" ); // same as nmethod::compile_kind |
342 | } // else compile_kind='c2c' |
343 | if (!method.is_null()) log->method(method); |
344 | if (_osr_bci != CompileBroker::standard_entry_bci) { |
345 | log->print(" osr_bci='%d'" , _osr_bci); |
346 | } |
347 | if (_comp_level != CompLevel_highest_tier) { |
348 | log->print(" level='%d'" , _comp_level); |
349 | } |
350 | if (_is_blocking) { |
351 | log->print(" blocking='1'" ); |
352 | } |
353 | log->stamp(); |
354 | } |
355 | |
356 | // ------------------------------------------------------------------ |
357 | // CompileTask::log_task_queued |
358 | void CompileTask::log_task_queued() { |
359 | Thread* thread = Thread::current(); |
360 | ttyLocker ttyl; |
361 | ResourceMark rm(thread); |
362 | |
363 | xtty->begin_elem("task_queued" ); |
364 | log_task(xtty); |
365 | assert(_compile_reason > CompileTask::Reason_None && _compile_reason < CompileTask::Reason_Count, "Valid values" ); |
366 | xtty->print(" comment='%s'" , reason_name(_compile_reason)); |
367 | |
368 | if (_hot_method != NULL) { |
369 | methodHandle hot(thread, _hot_method); |
370 | methodHandle method(thread, _method); |
371 | if (hot() != method()) { |
372 | xtty->method(hot); |
373 | } |
374 | } |
375 | if (_hot_count != 0) { |
376 | xtty->print(" hot_count='%d'" , _hot_count); |
377 | } |
378 | xtty->end_elem(); |
379 | } |
380 | |
381 | |
382 | // ------------------------------------------------------------------ |
383 | // CompileTask::log_task_start |
384 | void CompileTask::log_task_start(CompileLog* log) { |
385 | log->begin_head("task" ); |
386 | log_task(log); |
387 | log->end_head(); |
388 | } |
389 | |
390 | |
391 | // ------------------------------------------------------------------ |
392 | // CompileTask::log_task_done |
393 | void CompileTask::log_task_done(CompileLog* log) { |
394 | Thread* thread = Thread::current(); |
395 | methodHandle method(thread, this->method()); |
396 | ResourceMark rm(thread); |
397 | |
398 | if (!_is_success) { |
399 | assert(_failure_reason != NULL, "missing" ); |
400 | const char* reason = _failure_reason != NULL ? _failure_reason : "unknown" ; |
401 | log->elem("failure reason='%s'" , reason); |
402 | } |
403 | |
404 | // <task_done ... stamp='1.234'> </task> |
405 | nmethod* nm = code(); |
406 | log->begin_elem("task_done success='%d' nmsize='%d' count='%d'" , |
407 | _is_success, nm == NULL ? 0 : nm->content_size(), |
408 | method->invocation_count()); |
409 | int bec = method->backedge_count(); |
410 | if (bec != 0) log->print(" backedge_count='%d'" , bec); |
411 | // Note: "_is_complete" is about to be set, but is not. |
412 | if (_num_inlined_bytecodes != 0) { |
413 | log->print(" inlined_bytes='%d'" , _num_inlined_bytecodes); |
414 | } |
415 | log->stamp(); |
416 | log->end_elem(); |
417 | log->clear_identities(); // next task will have different CI |
418 | log->tail("task" ); |
419 | log->flush(); |
420 | log->mark_file_end(); |
421 | } |
422 | |
423 | // ------------------------------------------------------------------ |
424 | // CompileTask::check_break_at_flags |
425 | bool CompileTask::check_break_at_flags() { |
426 | int compile_id = this->_compile_id; |
427 | bool is_osr = (_osr_bci != CompileBroker::standard_entry_bci); |
428 | |
429 | if (CICountOSR && is_osr && (compile_id == CIBreakAtOSR)) { |
430 | return true; |
431 | } else { |
432 | return (compile_id == CIBreakAt); |
433 | } |
434 | } |
435 | |
436 | // ------------------------------------------------------------------ |
437 | // CompileTask::print_inlining |
438 | void CompileTask::print_inlining_inner(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg) { |
439 | // 1234567 |
440 | st->print(" " ); // print timestamp |
441 | // 1234 |
442 | st->print(" " ); // print compilation number |
443 | |
444 | // method attributes |
445 | if (method->is_loaded()) { |
446 | const char sync_char = method->is_synchronized() ? 's' : ' '; |
447 | const char exception_char = method->has_exception_handlers() ? '!' : ' '; |
448 | const char monitors_char = method->has_monitor_bytecodes() ? 'm' : ' '; |
449 | |
450 | // print method attributes |
451 | st->print(" %c%c%c " , sync_char, exception_char, monitors_char); |
452 | } else { |
453 | // %s!bn |
454 | st->print(" " ); // print method attributes |
455 | } |
456 | |
457 | if (TieredCompilation) { |
458 | st->print(" " ); |
459 | } |
460 | st->print(" " ); // more indent |
461 | st->print(" " ); // initial inlining indent |
462 | |
463 | for (int i = 0; i < inline_level; i++) st->print(" " ); |
464 | |
465 | st->print("@ %d " , bci); // print bci |
466 | method->print_short_name(st); |
467 | if (method->is_loaded()) |
468 | st->print(" (%d bytes)" , method->code_size()); |
469 | else |
470 | st->print(" (not loaded)" ); |
471 | |
472 | if (msg != NULL) { |
473 | st->print(" %s" , msg); |
474 | } |
475 | st->cr(); |
476 | } |
477 | |
478 | void CompileTask::print_ul(const char* msg){ |
479 | LogTarget(Debug, jit, compilation) lt; |
480 | if (lt.is_enabled()) { |
481 | LogStream ls(lt); |
482 | print(&ls, msg, /* short form */ true, /* cr */ true); |
483 | } |
484 | } |
485 | |
486 | void CompileTask::print_ul(const nmethod* nm, const char* msg) { |
487 | LogTarget(Debug, jit, compilation) lt; |
488 | if (lt.is_enabled()) { |
489 | LogStream ls(lt); |
490 | print_impl(&ls, nm->method(), nm->compile_id(), |
491 | nm->comp_level(), nm->is_osr_method(), |
492 | nm->is_osr_method() ? nm->osr_entry_bci() : -1, |
493 | /*is_blocking*/ false, |
494 | msg, /* short form */ true, /* cr */ true); |
495 | } |
496 | } |
497 | |
498 | void CompileTask::print_inlining_ul(ciMethod* method, int inline_level, int bci, const char* msg) { |
499 | LogTarget(Debug, jit, inlining) lt; |
500 | if (lt.is_enabled()) { |
501 | LogStream ls(lt); |
502 | print_inlining_inner(&ls, method, inline_level, bci, msg); |
503 | } |
504 | } |
505 | |
506 | |