1 /*
2 * Copyright (c) 2023, 2026, 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/aotCompileBroker.hpp"
31 #include "compiler/compilationPolicy.hpp"
32 #include "compiler/compileBroker.hpp"
33 #include "compiler/compiler_globals.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 AOTCompileIterator : StackObj {
40 private:
41 CompLevel _comp_level;
42 bool _for_preload;
43 Thread* _thread;
44 GrowableArray<Method*> _methods;
45
46 public:
47 AOTCompileIterator(CompLevel comp_level, bool for_preload, JavaThread* thread)
48 : _comp_level(comp_level), _for_preload(for_preload), _thread(thread) {
49 assert(TrainingData::have_data(), "sanity");
50 }
51
52 bool include(MethodTrainingData* mtd) {
53 Method* m = mtd->holder();
54 if (m->is_native() || m->is_abstract() || !m->method_holder()->is_linked()) {
55 return false;
56 }
57 DirectiveSet* directives = DirectivesStack::getMatchingDirective(methodHandle(_thread, m), nullptr);
58 if (directives->DontAOTCompileOption) {
59 return false;
60 }
61 if (directives->AOTCompileRecordedOption > 0) {
62 return true;
63 }
64 int high_top_level = mtd->highest_top_level();
65 switch (_comp_level) {
66 case CompLevel_simple:
67 case CompLevel_full_optimization:
68 // For final C1/C2 compilations, we only compile when there was relevant compilation during training.
69 return _comp_level == high_top_level;
70 case CompLevel_limited_profile:
71 // For profiled C1 compilations, generate limited profile when there was limited/full
72 // profiled compilation in training.
73 return CompLevel_limited_profile <= high_top_level && high_top_level <= CompLevel_full_profile;
74 case CompLevel_full_profile:
75 // We do not include C1 full profiled methods at this time.
76 // TODO: See if it is profitable to do so.
77 return false;
78 default:
79 assert(false, "Missed the case: %d", _comp_level);
80 }
81 // Do not include methods by default.
82 return false;
83 }
84
85 void apply(TrainingData* td) {
86 if (td->is_MethodTrainingData()) {
87 MethodTrainingData* mtd = td->as_MethodTrainingData();
88 if (mtd->has_holder() && include(mtd)) {
89 _methods.push(mtd->holder());
90 }
91 }
92 }
93
94 static MethodTrainingData* method_training_data(Method* m) {
95 if (m->method_holder()->is_loaded()) {
96 return MethodTrainingData::find(methodHandle(Thread::current(), m));
97 }
98 return nullptr;
99 }
100
101 // We sort methods by compile ID, presuming the methods that compiled earlier
102 // are more important. This only matters for preload code, which is loaded
103 // asynchronously; other levels are sorted for better consistency between training
104 // runs. Since we can accept methods from multiple levels, we use the compile ID
105 // from the lowest level.
106 static int compare_methods(Method** m1, Method** m2) {
107 int c1 = compile_id(*m1);
108 int c2 = compile_id(*m2);
109 if (c1 < c2) return -1;
110 if (c1 > c2) return +1;
111 return 0;
112 }
113
114 static int compile_id(Method* m) {
115 // Methods without recorded compilations are treated as "compiled last"
116 int id = INT_MAX;
117 MethodTrainingData* mtd = method_training_data(m);
118 if (mtd != nullptr) {
119 for (int level = CompLevel_simple; level <= CompilationPolicy::highest_compile_level(); level++) {
120 CompileTrainingData* ctd = mtd->last_toplevel_compile(level);
121 if (ctd != nullptr) {
122 id = MIN2(id, ctd->compile_id());
123 }
124 }
125 }
126 return id;
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_AOTCompileForPreload : CompileTask::Reason_AOTCompile,
142 THREAD);
143 if (HAS_PENDING_EXCEPTION) {
144 CLEAR_PENDING_EXCEPTION;
145 }
146 }
147 }
148
149 void print_compilation_status(ArchiveBuilder* builder) {
150 LogStreamHandle(Info, aot, compilation) logi;
151 if (!logi.is_enabled()) {
152 return;
153 }
154 int success_count = 0;
155 const int log_comp_level = _comp_level + (_for_preload ? 1 : 0);
156
157 for (int i = 0; i < _methods.length(); i++) {
158 Method* m = _methods.at(i);
159
160 bool is_success = !m->is_not_compilable(_comp_level);
161 if (is_success) {
162 success_count++;
163 }
164
165 LogStreamHandle(Debug, aot, compilation) log;
166 if (log.is_enabled()) {
167 ResourceMark rm;
168 log.print("[%4d] T%d Compiled %s [%p", i, log_comp_level, m->external_name(), m);
169 if (builder != nullptr) {
170 Method* requested_m = builder->to_requested(builder->get_buffered_addr(m));
171 log.print(" -> %p", requested_m);
172 }
173 log.print_cr("] {%d} [%d] (%s)", compile_id(m), AOTCodeCache::store_entries_cnt(), (is_success ? "success" : "FAILED"));
174 }
175 }
176
177 logi.print_cr("AOT Compilation for level %d finished (%d successful out of %d total)",
178 log_comp_level, success_count, _methods.length());
179 }
180
181 void compile(ArchiveBuilder* builder, TRAPS) {
182 _methods.sort(&compare_methods);
183 schedule_compilations(THREAD);
184 CompileBroker::wait_for_no_active_tasks();
185 print_compilation_status(builder);
186 }
187 };
188
189 void AOTCompileBroker::compile_aot_code(CompLevel comp_level, bool for_preload, TRAPS) {
190 ResourceMark rm;
191 AOTCompileIterator aci(comp_level, for_preload, THREAD);
192 TrainingData::iterate([&](TrainingData* td) {
193 aci.apply(td);
194 });
195 aci.compile((ArchiveBuilder*)nullptr, THREAD);
196 }
197
198 void AOTCompileBroker::compile_aot_code(TRAPS) {
199 if (!AOTCodeCache::is_dumping_code()) {
200 return;
201 }
202 log_info(aot, compilation)("AOT compilation started");
203 if (TrainingData::have_data()) {
204 TrainingData::iterate([&](TrainingData* td) {
205 if (td->is_KlassTrainingData()) {
206 KlassTrainingData *ktd = td->as_KlassTrainingData();
207 if (ktd->has_holder()) {
208 assert(!HAS_PENDING_EXCEPTION, "");
209 ktd->holder()->link_class(THREAD);
210 if (HAS_PENDING_EXCEPTION) {
211 LogStreamHandle(Warning, aot, compilation) log;
212 if (log.is_enabled()) {
213 ResourceMark rm;
214 log.print("Linkage failed for %s: ", ktd->holder()->external_name());
215 PENDING_EXCEPTION->print_on(&log);
216 }
217 CLEAR_PENDING_EXCEPTION;
218 }
219 }
220 }
221 });
222
223 CompLevel highest_level = CompilationPolicy::highest_compile_level();
224 if (highest_level >= CompLevel_full_optimization && ClassInitBarrierMode > 0) {
225 compile_aot_code(CompLevel_full_optimization, true, CHECK);
226 }
227 for (int level = CompLevel_simple; level <= highest_level; level++) {
228 compile_aot_code((CompLevel)level, false, CHECK);
229 }
230 }
231 }
232
233 void AOTCompileBroker::compile_aot_code(ArchiveBuilder* builder, TRAPS) {
234 assert(AOTCodeCache::is_dumping_code(), "sanity");
235 if (TrainingData::have_data()) {
236 ResourceMark rm;
237 CompLevel highest_level = CompilationPolicy::highest_compile_level();
238 if (highest_level >= CompLevel_full_optimization && ClassInitBarrierMode > 0) {
239 AOTCompileIterator aci(CompLevel_full_optimization, true /*for_preload*/, THREAD);
240 TrainingData::iterate([&](TrainingData* td) {
241 aci.apply(td);
242 });
243 aci.compile(builder, THREAD);
244 }
245
246 for (int level = CompLevel_simple; level <= highest_level; level++) {
247 AOTCompileIterator aci((CompLevel)level, false /*for_preload*/, THREAD);
248 TrainingData::iterate([&](TrainingData* td) {
249 aci.apply(td);
250 });
251 aci.compile(builder, THREAD);
252 }
253 }
254 }