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