1 /*
  2  * Copyright (c) 2023, 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 "precompiled.hpp"
 26 #include "cds/archiveBuilder.hpp"
 27 #include "cds/cdsAccess.hpp"
 28 #include "cds/cdsConfig.hpp"
 29 #include "cds/runTimeClassInfo.hpp"
 30 #include "code/SCCache.hpp"
 31 #include "compiler/compiler_globals.hpp"
 32 #include "compiler/compileBroker.hpp"
 33 #include "compiler/precompiler.hpp"
 34 #include "logging/logStream.hpp"
 35 #include "memory/allocation.hpp"
 36 #include "oops/trainingData.hpp"
 37 
 38 class PrecompileIterator : StackObj {
 39 private:
 40   CompLevel _comp_level;
 41   CompLevel _search_level;
 42   bool _for_preload;
 43   Thread* _thread;
 44   GrowableArray<Method*> _methods;
 45 
 46   nmethod* precompile(Method* m, TRAPS) {
 47     assert(m->method_holder()->is_linked(), "required");
 48 
 49     methodHandle mh(THREAD, m);
 50     assert(!HAS_PENDING_EXCEPTION, "");
 51     CompileTask::CompileReason compile_reason = (_for_preload ? CompileTask::Reason_PrecompileForPreload
 52                                                               : CompileTask::Reason_Precompile);
 53     return CompileBroker::compile_method(mh, InvocationEntryBci, _comp_level, methodHandle(), 0,
 54                                          true /*requires_online_comp*/, compile_reason,
 55                                          THREAD);
 56   }
 57 
 58   nmethod* precompile(Method* m, ArchiveBuilder* builder, TRAPS) {
 59     nmethod* code = precompile(m, THREAD);
 60     bool status = (!HAS_PENDING_EXCEPTION) && (code != nullptr);
 61 
 62     static int count = 0;
 63     static CompiledMethod* last = nullptr;
 64     Method* requested_m = builder->to_requested(builder->get_buffered_addr(m));
 65     ++count;
 66 
 67     LogStreamHandle(Info, precompile) log;
 68     if (log.is_enabled()) {
 69       ResourceMark rm;
 70       log.print("[%4d] T%d Compiled %s [%p -> %p] (%s)",
 71                 count, _comp_level + (_for_preload ? 1 : 0), m->external_name(), m, requested_m,
 72                              status ? "success" : "FAILED");
 73       if (status) {
 74         int isz = code->insts_size();
 75         int delta = (last != nullptr ? (int) (address(code) - address(last)) : 0);
 76         last = code;
 77 
 78         log.print(" code = %p insts_size = %d delta = %d", code, isz, delta);
 79       }
 80     }
 81     return code;
 82   }
 83 
 84 public:
 85   PrecompileIterator(CompLevel comp_level, bool for_preload, CompLevel search_level, JavaThread* thread)
 86   : _comp_level(comp_level), _search_level(search_level), _for_preload(for_preload), _thread(thread) {
 87     assert(TrainingData::have_data(), "sanity");
 88   }
 89 
 90   bool include(Method* m) {
 91     if (m->is_native() || m->is_abstract()) {
 92       return false;
 93     }
 94     DirectiveSet* directives = DirectivesStack::getMatchingDirective(methodHandle(_thread, m), nullptr);
 95     if (directives->DontPrecompileOption) {
 96       return false; // excluded
 97     } else if (directives->PrecompileRecordedOption > 0) {
 98       return true;
 99     }
100     int cid = compile_id(m, _search_level);
101     return (cid < INT_MAX);
102   }
103 
104   void do_value(const RunTimeClassInfo* record) {
105     Array<Method*>* methods = record->_klass->methods();
106     for (int i = 0; i < methods->length(); i++) {
107       Method* m = methods->at(i);
108       if (include(m)) {
109         _methods.push(m);
110       }
111     }
112   }
113   void do_value(TrainingData* td) {
114     if (td->is_MethodTrainingData()) {
115       MethodTrainingData* mtd = td->as_MethodTrainingData();
116       if (mtd->has_holder() && include((Method*)mtd->holder())) {
117         _methods.push((Method*)mtd->holder());
118       }
119     }
120   }
121 
122   static int compile_id(Method* m, int level) {
123     MethodTrainingData* mtd = TrainingData::lookup_for(m);
124     if (mtd != nullptr && mtd->highest_level() == level) {
125       CompileTrainingData* ctd = mtd->last_toplevel_compile(level);
126       if (ctd != nullptr) {
127         return ctd->compile_id();
128       }
129     }
130     return INT_MAX; // treat as the last compilation
131   }
132 
133   static int compare_by_compile_id(Method** m1, Method** m2, CompLevel comp_level) {
134     int id1 = compile_id(*m1, comp_level);
135     int id2 = compile_id(*m2, comp_level);
136     return (id1 - id2);
137   }
138 
139   static int compare_by_compile_id_tier1(Method** m1, Method** m2) {
140     return compare_by_compile_id(m1, m2, CompLevel_simple);
141   }
142 
143   static int compare_by_compile_id_tier2(Method** m1, Method** m2) {
144     return compare_by_compile_id(m1, m2, CompLevel_limited_profile);
145   }
146 
147   static int compare_by_compile_id_tier3(Method** m1, Method** m2) {
148     return compare_by_compile_id(m1, m2, CompLevel_full_profile);
149   }
150 
151   static int compare_by_compile_id_tier4(Method** m1, Method** m2) {
152     return compare_by_compile_id(m1, m2, CompLevel_full_optimization);
153   }
154 
155   void sort_methods_by_compile_id(GrowableArray<Method*>* methods) {
156     switch(_search_level) {
157       case CompLevel_simple:            methods->sort(&compare_by_compile_id_tier1); break;
158       case CompLevel_limited_profile:   methods->sort(&compare_by_compile_id_tier2); break;
159       case CompLevel_full_profile:      methods->sort(&compare_by_compile_id_tier3); break;
160       case CompLevel_full_optimization: methods->sort(&compare_by_compile_id_tier4); break;
161 
162       default: fatal("%d", _search_level);
163     }
164   }
165 
166   void precompile(ArchiveBuilder* builder, TRAPS) {
167     sort_methods_by_compile_id(&_methods);
168 
169     for (int i = 0; i < _methods.length(); i++) {
170       Method* m = _methods.at(i);
171 
172       assert(!HAS_PENDING_EXCEPTION, "");
173       precompile(m, builder, THREAD);
174       if (HAS_PENDING_EXCEPTION) {
175         CLEAR_PENDING_EXCEPTION;
176       }
177     }
178   }
179 };
180 
181 // New workflow only
182 void Precompiler::compile_cached_code(ArchiveBuilder* builder, TRAPS) {
183   assert(CDSConfig::is_dumping_final_static_archive() && StoreCachedCode, "sanity");
184   if (TrainingData::have_data()) {
185     ResourceMark rm;
186 
187     SCCache::new_workflow_start_writing_cache();
188 
189     {
190       PrecompileIterator pi(CompLevel_full_optimization, true /*for_preload*/, CompLevel_full_optimization, THREAD);
191       TrainingData::archived_training_data_dictionary()->iterate(&pi);
192       pi.precompile(builder, THREAD);
193     }
194 
195     for (int level = CompLevel_simple; level <= CompLevel_full_optimization; level++) {
196       CompLevel comp_level = (CompLevel)level;
197       if (comp_level == CompLevel_full_profile) {
198         comp_level = CompLevel_limited_profile;
199       }
200       PrecompileIterator pi(comp_level, false /*for_preload*/, (CompLevel)level, THREAD);
201       TrainingData::archived_training_data_dictionary()->iterate(&pi);
202       pi.precompile(builder, THREAD);
203     }
204 
205     SCCache::new_workflow_end_writing_cache();
206   }
207 }