1 /*
2 * Copyright (c) 2023, 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
25 #include "cds/aotCacheAccess.hpp"
26 #include "cds/archiveBuilder.hpp"
27 #include "cds/cdsConfig.hpp"
28 #include "cds/runTimeClassInfo.hpp"
29 #include "code/aotCodeCache.hpp"
30 #include "compiler/compilationPolicy.hpp"
31 #include "compiler/compileBroker.hpp"
32 #include "compiler/compiler_globals.hpp"
33 #include "compiler/precompiler.hpp"
34 #include "logging/logStream.hpp"
35 #include "memory/allocation.hpp"
36 #include "oops/trainingData.hpp"
37 #include "runtime/handles.inline.hpp"
38
39 class PrecompileIterator : StackObj {
40 private:
41 CompLevel _comp_level;
42 CompLevel _search_level;
43 bool _for_preload;
44 Thread* _thread;
45 GrowableArray<Method*> _methods;
46
47 public:
48 PrecompileIterator(CompLevel comp_level, bool for_preload, CompLevel search_level, JavaThread* thread)
49 : _comp_level(comp_level), _search_level(search_level), _for_preload(for_preload), _thread(thread) {
50 assert(TrainingData::have_data(), "sanity");
51 }
52
53 bool include(Method* m) {
54 if (m->is_native() || m->is_abstract()) {
55 return false;
56 }
57 DirectiveSet* directives = DirectivesStack::getMatchingDirective(methodHandle(_thread, m), nullptr);
58 if (directives->DontPrecompileOption) {
59 return false; // excluded
60 } else if (directives->PrecompileRecordedOption > 0) {
61 return true;
62 }
63 int cid = compile_id(m, _search_level);
64 return (cid < INT_MAX);
65 }
66
67 void do_value(const RunTimeClassInfo* record) {
68 Array<Method*>* methods = record->klass()->methods();
69 for (int i = 0; i < methods->length(); i++) {
70 Method* m = methods->at(i);
71 if (include(m)) {
72 _methods.push(m);
73 }
74 }
75 }
76 void operator()(TrainingData* td) {
77 if (td->is_MethodTrainingData()) {
78 MethodTrainingData* mtd = td->as_MethodTrainingData();
79 if (mtd->has_holder() && include((Method*)mtd->holder())) {
80 _methods.push((Method*)mtd->holder());
81 }
82 }
83 }
84
85 static int compile_id(Method* m, int level) {
86 MethodTrainingData* mtd = m->method_holder()->is_loaded() ? MethodTrainingData::find(methodHandle(Thread::current(), m)) : nullptr;
87 if (mtd != nullptr && mtd->highest_level() == level) {
88 CompileTrainingData* ctd = mtd->last_toplevel_compile(level);
89 if (ctd != nullptr) {
90 return ctd->compile_id();
91 }
92 }
93 return INT_MAX; // treat as the last compilation
94 }
95
96 static int compare_by_compile_id(Method** m1, Method** m2, CompLevel comp_level) {
97 int id1 = compile_id(*m1, comp_level);
98 int id2 = compile_id(*m2, comp_level);
99 return (id1 - id2);
100 }
101
102 static int compare_by_compile_id_tier1(Method** m1, Method** m2) {
103 return compare_by_compile_id(m1, m2, CompLevel_simple);
104 }
105
106 static int compare_by_compile_id_tier2(Method** m1, Method** m2) {
107 return compare_by_compile_id(m1, m2, CompLevel_limited_profile);
108 }
109
110 static int compare_by_compile_id_tier3(Method** m1, Method** m2) {
111 return compare_by_compile_id(m1, m2, CompLevel_full_profile);
112 }
113
114 static int compare_by_compile_id_tier4(Method** m1, Method** m2) {
115 return compare_by_compile_id(m1, m2, CompLevel_full_optimization);
116 }
117
118 void sort_methods_by_compile_id() {
119 switch(_search_level) {
120 case CompLevel_simple: _methods.sort(&compare_by_compile_id_tier1); break;
121 case CompLevel_limited_profile: _methods.sort(&compare_by_compile_id_tier2); break;
122 case CompLevel_full_profile: _methods.sort(&compare_by_compile_id_tier3); break;
123 case CompLevel_full_optimization: _methods.sort(&compare_by_compile_id_tier4); break;
124
125 default: fatal("%d", _search_level);
126 }
127 }
128
129 void schedule_compilations(TRAPS) {
130 for (int i = 0; i < _methods.length(); i++) {
131 Method* m = _methods.at(i);
132 methodHandle mh(THREAD, m);
133 assert(mh()->method_holder()->is_linked(), "required");
134 if (!AOTCacheAccess::can_generate_aot_code(m)) {
135 continue; // Method is not archived
136 }
137 assert(!HAS_PENDING_EXCEPTION, "");
138 CompileBroker::compile_method(mh, InvocationEntryBci, _comp_level,
139 0,
140 true /*requires_online_comp*/,
141 _for_preload ? CompileTask::Reason_PrecompileForPreload : CompileTask::Reason_Precompile,
142 THREAD);
143 if (HAS_PENDING_EXCEPTION) {
144 CLEAR_PENDING_EXCEPTION;
145 }
146 }
147 }
148
149 void print_compilation_status(ArchiveBuilder* builder) {
150 int success_count = 0;
151 const int log_comp_level = _comp_level + (_for_preload ? 1 : 0);
152
153 for (int i = 0; i < _methods.length(); i++) {
154 Method* m = _methods.at(i);
155
156 bool is_success = !m->is_not_compilable(_comp_level);
157 if (is_success) {
158 success_count++;
159 }
160
161 LogStreamHandle(Info, precompile) log;
162 if (log.is_enabled()) {
163 ResourceMark rm;
164 log.print("[%4d] T%d Compiled %s [%p", i, log_comp_level, m->external_name(), m);
165 if (builder != nullptr) {
166 Method* requested_m = builder->to_requested(builder->get_buffered_addr(m));
167 log.print(" -> %p", requested_m);
168 }
169 log.print("] [%d] (%s)", AOTCodeCache::store_entries_cnt(), (is_success ? "success" : "FAILED"));
170 }
171 }
172
173 log_info(precompile)("Precompilation for level %d finished (%d successful out of %d total)",
174 log_comp_level, success_count, _methods.length());
175 }
176
177 void precompile(ArchiveBuilder* builder, TRAPS) {
178 sort_methods_by_compile_id();
179 schedule_compilations(THREAD);
180 CompileBroker::wait_for_no_active_tasks();
181 print_compilation_status(builder);
182 }
183 };
184
185 void Precompiler::compile_aot_code(CompLevel search_level, bool for_preload, CompLevel comp_level, TRAPS) {
186 ResourceMark rm;
187 PrecompileIterator pi(comp_level, for_preload, search_level, THREAD);
188 TrainingData::iterate(pi);
189 pi.precompile((ArchiveBuilder*)nullptr, THREAD);
190 }
191
192 void Precompiler::compile_aot_code(TRAPS) {
193 if (!AOTCodeCache::is_dumping_code()) {
194 return;
195 }
196 log_info(precompile)("Precompilation started");
197 if (TrainingData::have_data()) {
198 TrainingData::iterate([&](TrainingData* td) {
199 if (td->is_KlassTrainingData()) {
200 KlassTrainingData *ktd = td->as_KlassTrainingData();
201 if (ktd->has_holder()) {
202 assert(!HAS_PENDING_EXCEPTION, "");
203 ktd->holder()->link_class(THREAD);
204 if (HAS_PENDING_EXCEPTION) {
205 LogStreamHandle(Warning, precompile) log;
206 if (log.is_enabled()) {
207 ResourceMark rm;
208 log.print("Linkage failed for %s: ", ktd->holder()->external_name());
209 PENDING_EXCEPTION->print_on(&log);
210 }
211 CLEAR_PENDING_EXCEPTION;
212 }
213 }
214 }
215 });
216
217 if (ClassInitBarrierMode > 0) { // Preload code is enabled
218 compile_aot_code(CompLevel_full_optimization, true, CompLevel_full_optimization, CHECK);
219 }
220 compile_aot_code(CompLevel_full_optimization, false, CompLevel_full_optimization, CHECK);
221 compile_aot_code(CompLevel_full_profile, false, CompLevel_limited_profile, CHECK);
222 compile_aot_code(CompLevel_limited_profile, false, CompLevel_limited_profile, CHECK);
223 compile_aot_code(CompLevel_simple, false, CompLevel_simple, CHECK);
224 }
225 }
226
227 // New workflow only
228 void Precompiler::compile_aot_code(ArchiveBuilder* builder, TRAPS) {
229 assert(AOTCodeCache::is_dumping_code(), "sanity");
230 if (TrainingData::have_data()) {
231 ResourceMark rm;
232 CompLevel highest_level = CompilationPolicy::highest_compile_level();
233 if (highest_level >= CompLevel_full_optimization && ClassInitBarrierMode > 0) {
234 PrecompileIterator pi(CompLevel_full_optimization, true /*for_preload*/, CompLevel_full_optimization, THREAD);
235 TrainingData::iterate(pi);
236 pi.precompile(builder, THREAD);
237 }
238
239 for (int level = CompLevel_simple; level <= highest_level; level++) {
240 CompLevel comp_level = (CompLevel)level;
241 if (comp_level == CompLevel_full_profile) {
242 comp_level = CompLevel_limited_profile;
243 }
244 PrecompileIterator pi(comp_level, false /*for_preload*/, (CompLevel)level, THREAD);
245 TrainingData::iterate(pi);
246 pi.precompile(builder, THREAD);
247 }
248 }
249 }