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