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 }