blob: 7ed70971a30f19c493ebcebc36a88fa4d410863d [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
19#include "arch/instruction_set.h"
20#include "arch/instruction_set_features.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010021#include "base/time_utils.h"
Mathieu Chartiera4885cb2015-03-09 15:38:54 -070022#include "base/timing_logger.h"
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080023#include "compiler_callbacks.h"
24#include "dex/pass_manager.h"
25#include "dex/quick_compiler_callbacks.h"
26#include "driver/compiler_driver.h"
27#include "driver/compiler_options.h"
28#include "jit/jit.h"
29#include "jit/jit_code_cache.h"
30#include "mirror/art_method-inl.h"
31#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
57extern "C" bool jit_compile_method(void* handle, mirror::ArtMethod* method, Thread* self)
58 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
59 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,
74 false,
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080075 CompilerOptions::kDefaultTopKProfileThreshold,
Andreas Gampe7b2f09e2015-03-02 14:07:33 -080076 false, // TODO: Think about debuggability of JIT-compiled code.
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080077 false,
78 false,
79 false,
80 false,
David Srbecky8dc73242015-04-12 11:40:39 +010081 false,
Mathieu Chartierdce71f32015-02-27 14:24:37 -080082 false, // pic
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080083 nullptr,
84 pass_manager_options,
Andreas Gampe6cf49e52015-03-05 13:08:45 -080085 nullptr,
86 false));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080087 const InstructionSet instruction_set = kRuntimeISA;
88 instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
89 cumulative_logger_.reset(new CumulativeLogger("jit times"));
90 verification_results_.reset(new VerificationResults(compiler_options_.get()));
91 method_inliner_map_.reset(new DexFileToMethodInlinerMap);
92 callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
Andreas Gampe81c6f8d2015-03-25 17:19:53 -070093 method_inliner_map_.get(),
Andreas Gampe4585f872015-03-27 23:45:15 -070094 CompilerCallbacks::CallbackMode::kCompileApp));
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080095 compiler_driver_.reset(new CompilerDriver(
96 compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(),
97 Compiler::kQuick, instruction_set, instruction_set_features_.get(), false,
Andreas Gampe70bef0d2015-04-15 02:37:28 -070098 nullptr, nullptr, nullptr, 1, false, true,
Mathieu Chartiere5f13e52015-02-24 09:37:21 -080099 std::string(), cumulative_logger_.get(), -1, std::string()));
100 // Disable dedupe so we can remove compiled methods.
101 compiler_driver_->SetDedupeEnabled(false);
102 compiler_driver_->SetSupportBootImageFixup(false);
103}
104
105JitCompiler::~JitCompiler() {
106}
107
108bool JitCompiler::CompileMethod(Thread* self, mirror::ArtMethod* method) {
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700109 TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
Mathieu Chartier9b34b242015-03-09 11:30:17 -0700110 const uint64_t start_time = NanoTime();
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800111 StackHandleScope<2> hs(self);
112 self->AssertNoPendingException();
113 Runtime* runtime = Runtime::Current();
114 Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
115 if (runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) {
116 VLOG(jit) << "Already compiled " << PrettyMethod(method);
117 return true; // Already compiled
118 }
119 Handle<mirror::Class> h_class(hs.NewHandle(h_method->GetDeclaringClass()));
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700120 {
121 TimingLogger::ScopedTiming t2("Initializing", &logger);
122 if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
123 VLOG(jit) << "JIT failed to initialize " << PrettyMethod(h_method.Get());
124 return false;
125 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800126 }
127 const DexFile* dex_file = h_class->GetDexCache()->GetDexFile();
128 MethodReference method_ref(dex_file, h_method->GetDexMethodIndex());
129 // Only verify if we don't already have verification results.
130 if (verification_results_->GetVerifiedMethod(method_ref) == nullptr) {
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700131 TimingLogger::ScopedTiming t2("Verifying", &logger);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800132 std::string error;
133 if (verifier::MethodVerifier::VerifyMethod(h_method.Get(), true, &error) ==
134 verifier::MethodVerifier::kHardFailure) {
135 VLOG(jit) << "Not compile method " << PrettyMethod(h_method.Get())
136 << " due to verification failure " << error;
137 return false;
138 }
139 }
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700140 CompiledMethod* compiled_method = nullptr;
141 {
142 TimingLogger::ScopedTiming t2("Compiling", &logger);
143 compiled_method = compiler_driver_->CompileMethod(self, h_method.Get());
144 }
145 {
146 TimingLogger::ScopedTiming t2("TrimMaps", &logger);
147 // Trim maps to reduce memory usage, TODO: measure how much this increases compile time.
148 runtime->GetArenaPool()->TrimMaps();
149 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800150 if (compiled_method == nullptr) {
151 return false;
152 }
153 total_time_ += NanoTime() - start_time;
Mathieu Chartierc0d5f892015-02-25 13:22:57 -0800154 // Don't add the method if we are supposed to be deoptimized.
155 bool result = false;
156 if (!runtime->GetInstrumentation()->AreAllMethodsDeoptimized()) {
Mathieu Chartier9b34b242015-03-09 11:30:17 -0700157 const void* code = runtime->GetClassLinker()->GetOatMethodQuickCodeFor(
Mathieu Chartierc0d5f892015-02-25 13:22:57 -0800158 h_method.Get());
159 if (code != nullptr) {
160 // Already have some compiled code, just use this instead of linking.
161 // TODO: Fix recompilation.
162 h_method->SetEntryPointFromQuickCompiledCode(code);
163 result = true;
164 } else {
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700165 TimingLogger::ScopedTiming t2("MakeExecutable", &logger);
Mathieu Chartierc0d5f892015-02-25 13:22:57 -0800166 result = MakeExecutable(compiled_method, h_method.Get());
167 }
168 }
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800169 // Remove the compiled method to save memory.
170 compiler_driver_->RemoveCompiledMethod(method_ref);
Mathieu Chartiera4885cb2015-03-09 15:38:54 -0700171 runtime->GetJit()->AddTimingLogger(logger);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800172 return result;
173}
174
175CompilerCallbacks* JitCompiler::GetCompilerCallbacks() const {
176 return callbacks_.get();
177}
178
179uint8_t* JitCompiler::WriteMethodHeaderAndCode(const CompiledMethod* compiled_method,
180 uint8_t* reserve_begin, uint8_t* reserve_end,
181 const uint8_t* mapping_table,
182 const uint8_t* vmap_table,
183 const uint8_t* gc_map) {
184 reserve_begin += sizeof(OatQuickMethodHeader);
185 reserve_begin = reinterpret_cast<uint8_t*>(
186 compiled_method->AlignCode(reinterpret_cast<uintptr_t>(reserve_begin)));
187 const auto* quick_code = compiled_method->GetQuickCode();
188 CHECK_LE(reserve_begin, reserve_end);
189 CHECK_LE(quick_code->size(), static_cast<size_t>(reserve_end - reserve_begin));
190 auto* code_ptr = reserve_begin;
191 OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(code_ptr) - 1;
192 // Construct the header last.
193 const auto frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
194 const auto core_spill_mask = compiled_method->GetCoreSpillMask();
195 const auto fp_spill_mask = compiled_method->GetFpSpillMask();
196 const auto code_size = quick_code->size();
197 CHECK_NE(code_size, 0U);
198 std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr);
199 // After we are done writing we need to update the method header.
200 // Write out the method header last.
201 method_header = new(method_header)OatQuickMethodHeader(
202 code_ptr - mapping_table, code_ptr - vmap_table, code_ptr - gc_map, frame_size_in_bytes,
203 core_spill_mask, fp_spill_mask, code_size);
204 // Return the code ptr.
205 return code_ptr;
206}
207
208bool JitCompiler::AddToCodeCache(mirror::ArtMethod* method, const CompiledMethod* compiled_method,
209 OatFile::OatMethod* out_method) {
210 Runtime* runtime = Runtime::Current();
211 JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
212 const auto* quick_code = compiled_method->GetQuickCode();
213 if (quick_code == nullptr) {
214 return false;
215 }
216 const auto code_size = quick_code->size();
217 Thread* const self = Thread::Current();
218 const uint8_t* base = code_cache->CodeCachePtr();
219 auto* const mapping_table = compiled_method->GetMappingTable();
220 auto* const vmap_table = compiled_method->GetVmapTable();
221 auto* const gc_map = compiled_method->GetGcMap();
Mathieu Chartierb4e18082015-03-22 13:52:48 -0700222 CHECK(gc_map != nullptr) << PrettyMethod(method);
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800223 // Write out pre-header stuff.
224 uint8_t* const mapping_table_ptr = code_cache->AddDataArray(
225 self, mapping_table->data(), mapping_table->data() + mapping_table->size());
Mathieu Chartierb4e18082015-03-22 13:52:48 -0700226 if (mapping_table_ptr == nullptr) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800227 return false; // Out of data cache.
228 }
229 uint8_t* const vmap_table_ptr = code_cache->AddDataArray(
230 self, vmap_table->data(), vmap_table->data() + vmap_table->size());
Mathieu Chartierb4e18082015-03-22 13:52:48 -0700231 if (vmap_table_ptr == nullptr) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800232 return false; // Out of data cache.
233 }
234 uint8_t* const gc_map_ptr = code_cache->AddDataArray(
235 self, gc_map->data(), gc_map->data() + gc_map->size());
Mathieu Chartierb4e18082015-03-22 13:52:48 -0700236 if (gc_map_ptr == nullptr) {
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800237 return false; // Out of data cache.
238 }
239 // Don't touch this until you protect / unprotect the code.
240 const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32;
241 uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size);
242 if (code_reserve == nullptr) {
243 return false;
244 }
245 auto* code_ptr = WriteMethodHeaderAndCode(
246 compiled_method, code_reserve, code_reserve + reserve_size, mapping_table_ptr,
247 vmap_table_ptr, gc_map_ptr);
248
249 const size_t thumb_offset = compiled_method->CodeDelta();
250 const uint32_t code_offset = code_ptr - base + thumb_offset;
251 *out_method = OatFile::OatMethod(base, code_offset);
252 DCHECK_EQ(out_method->GetGcMap(), gc_map_ptr);
253 DCHECK_EQ(out_method->GetMappingTable(), mapping_table_ptr);
254 DCHECK_EQ(out_method->GetVmapTable(), vmap_table_ptr);
255 DCHECK_EQ(out_method->GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
256 DCHECK_EQ(out_method->GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
257 DCHECK_EQ(out_method->GetFpSpillMask(), compiled_method->GetFpSpillMask());
258 VLOG(jit) << "JIT added " << PrettyMethod(method) << "@" << method << " ccache_size="
259 << PrettySize(code_cache->CodeCacheSize()) << ": " << reinterpret_cast<void*>(code_ptr)
260 << "," << reinterpret_cast<void*>(code_ptr + code_size);
261 return true;
262}
263
264bool JitCompiler::MakeExecutable(CompiledMethod* compiled_method, mirror::ArtMethod* method) {
265 CHECK(method != nullptr);
266 CHECK(compiled_method != nullptr);
267 OatFile::OatMethod oat_method(nullptr, 0);
268 if (!AddToCodeCache(method, compiled_method, &oat_method)) {
269 return false;
270 }
271 // TODO: Flush instruction cache.
272 oat_method.LinkMethod(method);
273 CHECK(Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method))
274 << PrettyMethod(method);
275 return true;
276}
277
278} // namespace jit
279} // namespace art