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/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 bool _for_preload;
43 Thread* _thread;
44 GrowableArray<Method*> _methods;
45
46 public:
47 PrecompileIterator(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->DontPrecompileOption) {
59 return false;
60 }
61 if (directives->PrecompileRecordedOption > 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_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} [%d] (%s)", compile_id(m), 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 _methods.sort(&compare_methods);
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 comp_level, bool for_preload, TRAPS) {
186 ResourceMark rm;
187 PrecompileIterator pi(comp_level, for_preload, THREAD);
188 TrainingData::iterate([&](TrainingData* td) {
189 pi.apply(td);
190 });
191 pi.precompile((ArchiveBuilder*)nullptr, THREAD);
192 }
193
194 void Precompiler::compile_aot_code(TRAPS) {
195 if (!AOTCodeCache::is_dumping_code()) {
196 return;
197 }
198 log_info(precompile)("Precompilation started");
199 if (TrainingData::have_data()) {
200 TrainingData::iterate([&](TrainingData* td) {
201 if (td->is_KlassTrainingData()) {
202 KlassTrainingData *ktd = td->as_KlassTrainingData();
203 if (ktd->has_holder()) {
204 assert(!HAS_PENDING_EXCEPTION, "");
205 ktd->holder()->link_class(THREAD);
206 if (HAS_PENDING_EXCEPTION) {
207 LogStreamHandle(Warning, precompile) log;
208 if (log.is_enabled()) {
209 ResourceMark rm;
210 log.print("Linkage failed for %s: ", ktd->holder()->external_name());
211 PENDING_EXCEPTION->print_on(&log);
212 }
213 CLEAR_PENDING_EXCEPTION;
214 }
215 }
216 }
217 });
218
219 CompLevel highest_level = CompilationPolicy::highest_compile_level();
220 if (highest_level >= CompLevel_full_optimization && ClassInitBarrierMode > 0) {
221 compile_aot_code(CompLevel_full_optimization, true, CHECK);
222 }
223 for (int level = CompLevel_simple; level <= highest_level; level++) {
224 compile_aot_code((CompLevel)level, false, CHECK);
225 }
226 }
227 }
228
229 // New workflow only
230 void Precompiler::compile_aot_code(ArchiveBuilder* builder, TRAPS) {
231 assert(AOTCodeCache::is_dumping_code(), "sanity");
232 if (TrainingData::have_data()) {
233 ResourceMark rm;
234 CompLevel highest_level = CompilationPolicy::highest_compile_level();
235 if (highest_level >= CompLevel_full_optimization && ClassInitBarrierMode > 0) {
236 PrecompileIterator pi(CompLevel_full_optimization, true /*for_preload*/, THREAD);
237 TrainingData::iterate([&](TrainingData* td) {
238 pi.apply(td);
239 });
240 pi.precompile(builder, THREAD);
241 }
242
243 for (int level = CompLevel_simple; level <= highest_level; level++) {
244 PrecompileIterator pi((CompLevel)level, false /*for_preload*/, THREAD);
245 TrainingData::iterate([&](TrainingData* td) {
246 pi.apply(td);
247 });
248 pi.precompile(builder, THREAD);
249 }
250 }
251 }