blob: cd492020256a388ce0347f0d6e710113ab9dabdb [file] [log] [blame]
Mathieu Chartiere5f13e52015-02-24 09:37:21 -08001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jit_compiler.h"
18
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "art_method-inl.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080020#include "arch/instruction_set.h"
21#include "arch/instruction_set_features.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010022#include "base/time_utils.h"
Mathieu Chartiera4885cb2015-03-09 15:38:54 -070023#include "base/timing_logger.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080024#include "compiler_callbacks.h"
25#include "dex/pass_manager.h"
26#include "dex/quick_compiler_callbacks.h"
27#include "driver/compiler_driver.h"
28#include "driver/compiler_options.h"
29#include "jit/jit.h"
30#include "jit/jit_code_cache.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080031#include "oat_file-inl.h"
32#include "object_lock.h"
33#include "thread_list.h"
34#include "verifier/method_verifier-inl.h"
35
36namespace art {
37namespace jit {
38
39JitCompiler* JitCompiler::Create() {
40 return new JitCompiler();
41}
42
43extern "C" void* jit_load(CompilerCallbacks** callbacks) {
44 VLOG(jit) << "loading jit compiler";
45 auto* const jit_compiler = JitCompiler::Create();
46 CHECK(jit_compiler != nullptr);
47 *callbacks = jit_compiler->GetCompilerCallbacks();
48 VLOG(jit) << "Done loading jit compiler";
49 return jit_compiler;
50}
51
52extern "C" void jit_unload(void* handle) {
53 DCHECK(handle != nullptr);
54 delete reinterpret_cast<JitCompiler*>(handle);
55}
56
Mathieu Chartiere401d142015-04-22 13:56:20 -070057extern "C" bool jit_compile_method(void* handle, ArtMethod* method, Thread* self)
Mathieu Chartier90443472015-07-16 20:32:27 -070058 SHARED_REQUIRES(Locks::mutator_lock_) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080059 auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
60 DCHECK(jit_compiler != nullptr);
61 return jit_compiler->CompileMethod(self, method);
62}
63
64JitCompiler::JitCompiler() : total_time_(0) {
65 auto* pass_manager_options = new PassManagerOptions;
Mathieu Chartierf36cb5f2015-04-24 16:55:16 -070066 pass_manager_options->SetDisablePassList("GVN,DCE,GVNCleanup");
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080067 compiler_options_.reset(new CompilerOptions(
68 CompilerOptions::kDefaultCompilerFilter,
69 CompilerOptions::kDefaultHugeMethodThreshold,
70 CompilerOptions::kDefaultLargeMethodThreshold,
71 CompilerOptions::kDefaultSmallMethodThreshold,
72 CompilerOptions::kDefaultTinyMethodThreshold,
73 CompilerOptions::kDefaultNumDexMethodsThreshold,
Calin Juravleec748352015-07-29 13:52:12 +010074 CompilerOptions::kDefaultInlineDepthLimit,
75 CompilerOptions::kDefaultInlineMaxCodeUnits,
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +010076 /* include_patch_information */ false,
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080077 CompilerOptions::kDefaultTopKProfileThreshold,
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +010078 Runtime::Current()->IsDebuggable(),
David Srbecky8363c772015-05-28 16:12:43 +010079 CompilerOptions::kDefaultGenerateDebugInfo,
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +010080 /* implicit_null_checks */ true,
81 /* implicit_so_checks */ true,
82 /* implicit_suspend_checks */ false,
83 /* pic */ true, // TODO: Support non-PIC in optimizing.
84 /* verbose_methods */ nullptr,
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080085 pass_manager_options,
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +010086 /* init_failure_output */ nullptr,
87 /* abort_on_hard_verifier_failure */ false));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080088 const InstructionSet instruction_set = kRuntimeISA;
89 instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
90 cumulative_logger_.reset(new CumulativeLogger("jit times"));
91 verification_results_.reset(new VerificationResults(compiler_options_.get()));
92 method_inliner_map_.reset(new DexFileToMethodInlinerMap);
93 callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
Andreas Gampe81c6f8d2015-03-25 17:19:53 -070094 method_inliner_map_.get(),
Andreas Gampe4585f872015-03-27 23:45:15 -070095 CompilerCallbacks::CallbackMode::kCompileApp));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080096 compiler_driver_.reset(new CompilerDriver(
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +010097 compiler_options_.get(),
98 verification_results_.get(),
99 method_inliner_map_.get(),
100 Compiler::kOptimizing,
101 instruction_set,
102 instruction_set_features_.get(),
103 /* image */ false,
104 /* image_classes */ nullptr,
105 /* compiled_classes */ nullptr,
106 /* compiled_methods */ nullptr,
107 /* thread_count */ 1,
108 /* dump_stats */ false,
109 /* dump_passes */ false,
110 /* dump_cfg_file_name */ "",
Calin Juravle87000a92015-08-24 15:34:44 +0100111 /* dump_cfg_append */ false,
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +0100112 cumulative_logger_.get(),
113 /* swap_fd */ -1,
114 /* profile_file */ ""));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800115 // Disable dedupe so we can remove compiled methods.
116 compiler_driver_->SetDedupeEnabled(false);
117 compiler_driver_->SetSupportBootImageFixup(false);
118}
119
120JitCompiler::~JitCompiler() {
121}
122
Mathieu Chartiere401d142015-04-22 13:56:20 -0700123bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method) {
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700124 TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
Mathieu Chartier9b34b242015-03-09 11:30:17 -0700125 const uint64_t start_time = NanoTime();
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800126 StackHandleScope<2> hs(self);
127 self->AssertNoPendingException();
128 Runtime* runtime = Runtime::Current();
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100129
130 // Check if the method is already compiled.
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800131 if (runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) {
132 VLOG(jit) << "Already compiled " << PrettyMethod(method);
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100133 return true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800134 }
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100135
136 // Don't compile the method if we are supposed to be deoptimized.
137 if (runtime->GetInstrumentation()->AreAllMethodsDeoptimized()) {
138 return false;
139 }
140
141 // Ensure the class is initialized.
Mathieu Chartiere401d142015-04-22 13:56:20 -0700142 Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100143 if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
144 VLOG(jit) << "JIT failed to initialize " << PrettyMethod(method);
145 return false;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800146 }
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100147
148 // Do the compilation.
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700149 CompiledMethod* compiled_method = nullptr;
150 {
151 TimingLogger::ScopedTiming t2("Compiling", &logger);
Andreas Gampe5eb0d382015-07-23 01:19:26 -0700152 compiled_method = compiler_driver_->CompileArtMethod(self, method);
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700153 }
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100154
155 // Trim maps to reduce memory usage.
156 // TODO: measure how much this increases compile time.
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700157 {
158 TimingLogger::ScopedTiming t2("TrimMaps", &logger);
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700159 runtime->GetArenaPool()->TrimMaps();
160 }
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100161
162 // Check if we failed compiling.
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800163 if (compiled_method == nullptr) {
164 return false;
165 }
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100166
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800167 total_time_ += NanoTime() - start_time;
Mathieu Chartierc0d5f892015-02-25 13:22:57 -0800168 bool result = false;
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100169 const void* code = runtime->GetClassLinker()->GetOatMethodQuickCodeFor(method);
170
171 if (code != nullptr) {
172 // Already have some compiled code, just use this instead of linking.
173 // TODO: Fix recompilation.
174 method->SetEntryPointFromQuickCompiledCode(code);
175 result = true;
176 } else {
177 TimingLogger::ScopedTiming t2("LinkCode", &logger);
178 OatFile::OatMethod oat_method(nullptr, 0);
179 if (AddToCodeCache(method, compiled_method, &oat_method)) {
180 oat_method.LinkMethod(method);
181 CHECK(runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) << PrettyMethod(method);
Mathieu Chartierc0d5f892015-02-25 13:22:57 -0800182 result = true;
Mathieu Chartierc0d5f892015-02-25 13:22:57 -0800183 }
184 }
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100185
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800186 // Remove the compiled method to save memory.
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100187 compiler_driver_->RemoveCompiledMethod(
188 MethodReference(h_class->GetDexCache()->GetDexFile(), method->GetDexMethodIndex()));
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700189 runtime->GetJit()->AddTimingLogger(logger);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800190 return result;
191}
192
193CompilerCallbacks* JitCompiler::GetCompilerCallbacks() const {
194 return callbacks_.get();
195}
196
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100197bool JitCompiler::AddToCodeCache(ArtMethod* method,
198 const CompiledMethod* compiled_method,
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800199 OatFile::OatMethod* out_method) {
200 Runtime* runtime = Runtime::Current();
201 JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
202 const auto* quick_code = compiled_method->GetQuickCode();
203 if (quick_code == nullptr) {
204 return false;
205 }
206 const auto code_size = quick_code->size();
207 Thread* const self = Thread::Current();
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800208 auto* const mapping_table = compiled_method->GetMappingTable();
209 auto* const vmap_table = compiled_method->GetVmapTable();
210 auto* const gc_map = compiled_method->GetGcMap();
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +0100211 uint8_t* mapping_table_ptr = nullptr;
212 uint8_t* vmap_table_ptr = nullptr;
213 uint8_t* gc_map_ptr = nullptr;
214
215 if (mapping_table != nullptr) {
216 // Write out pre-header stuff.
217 mapping_table_ptr = code_cache->AddDataArray(
218 self, mapping_table->data(), mapping_table->data() + mapping_table->size());
219 if (mapping_table_ptr == nullptr) {
220 return false; // Out of data cache.
221 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800222 }
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +0100223
224 if (vmap_table != nullptr) {
225 vmap_table_ptr = code_cache->AddDataArray(
226 self, vmap_table->data(), vmap_table->data() + vmap_table->size());
227 if (vmap_table_ptr == nullptr) {
228 return false; // Out of data cache.
229 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800230 }
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +0100231
232 if (gc_map != nullptr) {
233 gc_map_ptr = code_cache->AddDataArray(
234 self, gc_map->data(), gc_map->data() + gc_map->size());
235 if (gc_map_ptr == nullptr) {
236 return false; // Out of data cache.
237 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800238 }
Nicolas Geoffray7a4d0152015-07-10 17:29:39 +0100239
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100240 uint8_t* const code = code_cache->CommitCode(self,
241 mapping_table_ptr,
242 vmap_table_ptr,
243 gc_map_ptr,
244 compiled_method->GetFrameSizeInBytes(),
245 compiled_method->GetCoreSpillMask(),
246 compiled_method->GetFpSpillMask(),
247 compiled_method->GetQuickCode()->data(),
248 compiled_method->GetQuickCode()->size());
249
250 if (code == nullptr) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800251 return false;
252 }
Mathieu Chartier5783a742015-06-01 19:12:36 -0700253
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800254 const size_t thumb_offset = compiled_method->CodeDelta();
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100255 const uint32_t code_offset = sizeof(OatQuickMethodHeader) + thumb_offset;
256 *out_method = OatFile::OatMethod(code, code_offset);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800257 DCHECK_EQ(out_method->GetGcMap(), gc_map_ptr);
258 DCHECK_EQ(out_method->GetMappingTable(), mapping_table_ptr);
259 DCHECK_EQ(out_method->GetVmapTable(), vmap_table_ptr);
260 DCHECK_EQ(out_method->GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
261 DCHECK_EQ(out_method->GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
262 DCHECK_EQ(out_method->GetFpSpillMask(), compiled_method->GetFpSpillMask());
Nicolas Geoffray0c3c2662015-10-15 13:53:04 +0100263 VLOG(jit)
264 << "JIT added "
265 << PrettyMethod(method) << "@" << method
266 << " ccache_size=" << PrettySize(code_cache->CodeCacheSize()) << ": "
267 << reinterpret_cast<void*>(code + code_offset)
268 << "," << reinterpret_cast<void*>(code + code_offset + code_size);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800269 return true;
270}
271
272} // namespace jit
273} // namespace art