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 }