jit_compiler.cc revision bcd94c8ea9bde4e075c25fbdfb3a2ef6858eed7b
1/*
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"
21#include "art_method-inl.h"
22#include "base/stringpiece.h"
23#include "base/time_utils.h"
24#include "base/timing_logger.h"
25#include "base/unix_file/fd_file.h"
26#include "debug/elf_debug_writer.h"
27#include "driver/compiler_driver.h"
28#include "driver/compiler_options.h"
29#include "jit/debugger_interface.h"
30#include "jit/jit.h"
31#include "jit/jit_code_cache.h"
32#include "oat_file-inl.h"
33#include "oat_quick_method_header.h"
34#include "object_lock.h"
35#include "thread_list.h"
36
37namespace art {
38namespace jit {
39
40JitCompiler* JitCompiler::Create() {
41  return new JitCompiler();
42}
43
44extern "C" void* jit_load(bool* generate_debug_info) {
45  VLOG(jit) << "loading jit compiler";
46  auto* const jit_compiler = JitCompiler::Create();
47  CHECK(jit_compiler != nullptr);
48  *generate_debug_info = jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo();
49  VLOG(jit) << "Done loading jit compiler";
50  return jit_compiler;
51}
52
53extern "C" void jit_unload(void* handle) {
54  DCHECK(handle != nullptr);
55  delete reinterpret_cast<JitCompiler*>(handle);
56}
57
58extern "C" bool jit_compile_method(
59    void* handle, ArtMethod* method, Thread* self, bool osr)
60    SHARED_REQUIRES(Locks::mutator_lock_) {
61  auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
62  DCHECK(jit_compiler != nullptr);
63  return jit_compiler->CompileMethod(self, method, osr);
64}
65
66extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t count)
67    SHARED_REQUIRES(Locks::mutator_lock_) {
68  auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
69  DCHECK(jit_compiler != nullptr);
70  if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) {
71    const ArrayRef<mirror::Class*> types_array(types, count);
72    ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForClasses(kRuntimeISA, types_array);
73    CreateJITCodeEntry(std::unique_ptr<const uint8_t[]>(elf_file.data()), elf_file.size());
74  }
75}
76
77// Callers of this method assume it has NO_RETURN.
78NO_RETURN static void Usage(const char* fmt, ...) {
79  va_list ap;
80  va_start(ap, fmt);
81  std::string error;
82  StringAppendV(&error, fmt, ap);
83  LOG(FATAL) << error;
84  va_end(ap);
85  exit(EXIT_FAILURE);
86}
87
88JitCompiler::JitCompiler() {
89  compiler_options_.reset(new CompilerOptions(
90      CompilerOptions::kDefaultCompilerFilter,
91      CompilerOptions::kDefaultHugeMethodThreshold,
92      CompilerOptions::kDefaultLargeMethodThreshold,
93      CompilerOptions::kDefaultSmallMethodThreshold,
94      CompilerOptions::kDefaultTinyMethodThreshold,
95      CompilerOptions::kDefaultNumDexMethodsThreshold,
96      CompilerOptions::kDefaultInlineDepthLimit,
97      CompilerOptions::kDefaultInlineMaxCodeUnits,
98      /* no_inline_from */ nullptr,
99      /* include_patch_information */ false,
100      CompilerOptions::kDefaultTopKProfileThreshold,
101      Runtime::Current()->IsDebuggable(),
102      CompilerOptions::kDefaultGenerateDebugInfo,
103      /* implicit_null_checks */ true,
104      /* implicit_so_checks */ true,
105      /* implicit_suspend_checks */ false,
106      /* pic */ true,  // TODO: Support non-PIC in optimizing.
107      /* verbose_methods */ nullptr,
108      /* init_failure_output */ nullptr,
109      /* abort_on_hard_verifier_failure */ false,
110      /* dump_cfg_file_name */ "",
111      /* dump_cfg_append */ false,
112      /* force_determinism */ false));
113  for (const std::string& argument : Runtime::Current()->GetCompilerOptions()) {
114    compiler_options_->ParseCompilerOption(argument, Usage);
115  }
116  const InstructionSet instruction_set = kRuntimeISA;
117  for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) {
118    VLOG(compiler) << "JIT compiler option " << option;
119    std::string error_msg;
120    if (option.starts_with("--instruction-set-variant=")) {
121      StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
122      VLOG(compiler) << "JIT instruction set variant " << str;
123      instruction_set_features_.reset(InstructionSetFeatures::FromVariant(
124          instruction_set, str.as_string(), &error_msg));
125      if (instruction_set_features_ == nullptr) {
126        LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
127      }
128    } else if (option.starts_with("--instruction-set-features=")) {
129      StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
130      VLOG(compiler) << "JIT instruction set features " << str;
131      if (instruction_set_features_.get() == nullptr) {
132        instruction_set_features_.reset(InstructionSetFeatures::FromVariant(
133            instruction_set, "default", &error_msg));
134        if (instruction_set_features_ == nullptr) {
135          LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
136        }
137      }
138      instruction_set_features_.reset(
139          instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg));
140      if (instruction_set_features_ == nullptr) {
141        LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
142      }
143    }
144  }
145  if (instruction_set_features_ == nullptr) {
146    instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
147  }
148  cumulative_logger_.reset(new CumulativeLogger("jit times"));
149  method_inliner_map_.reset(new DexFileToMethodInlinerMap);
150  compiler_driver_.reset(new CompilerDriver(
151      compiler_options_.get(),
152      /* verification_results */ nullptr,
153      method_inliner_map_.get(),
154      Compiler::kOptimizing,
155      instruction_set,
156      instruction_set_features_.get(),
157      /* image */ false,
158      /* image_classes */ nullptr,
159      /* compiled_classes */ nullptr,
160      /* compiled_methods */ nullptr,
161      /* thread_count */ 1,
162      /* dump_stats */ false,
163      /* dump_passes */ false,
164      cumulative_logger_.get(),
165      /* swap_fd */ -1,
166      /* profile_compilation_info */ nullptr));
167  // Disable dedupe so we can remove compiled methods.
168  compiler_driver_->SetDedupeEnabled(false);
169  compiler_driver_->SetSupportBootImageFixup(false);
170
171  if (compiler_options_->GetGenerateDebugInfo()) {
172#ifdef __ANDROID__
173    const char* prefix = "/data/misc/trace";
174#else
175    const char* prefix = "/tmp";
176#endif
177    DCHECK_EQ(compiler_driver_->GetThreadCount(), 1u)
178        << "Generating debug info only works with one compiler thread";
179    std::string perf_filename = std::string(prefix) + "/perf-" + std::to_string(getpid()) + ".map";
180    perf_file_.reset(OS::CreateEmptyFileWriteOnly(perf_filename.c_str()));
181    if (perf_file_ == nullptr) {
182      LOG(ERROR) << "Could not create perf file at " << perf_filename <<
183                    " Are you on a user build? Perf only works on userdebug/eng builds";
184    }
185  }
186}
187
188JitCompiler::~JitCompiler() {
189  if (perf_file_ != nullptr) {
190    UNUSED(perf_file_->Flush());
191    UNUSED(perf_file_->Close());
192  }
193}
194
195bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
196  DCHECK(!method->IsProxyMethod());
197  TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
198  StackHandleScope<2> hs(self);
199  self->AssertNoPendingException();
200  Runtime* runtime = Runtime::Current();
201
202  // Ensure the class is initialized.
203  Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
204  if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
205    VLOG(jit) << "JIT failed to initialize " << PrettyMethod(method);
206    return false;
207  }
208
209  // Do the compilation.
210  bool success = false;
211  {
212    TimingLogger::ScopedTiming t2("Compiling", &logger);
213    JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
214    success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method, osr);
215    if (success && (perf_file_ != nullptr)) {
216      const void* ptr = method->GetEntryPointFromQuickCompiledCode();
217      std::ostringstream stream;
218      stream << std::hex
219             << reinterpret_cast<uintptr_t>(ptr)
220             << " "
221             << code_cache->GetMemorySizeOfCodePointer(ptr)
222             << " "
223             << PrettyMethod(method)
224             << std::endl;
225      std::string str = stream.str();
226      bool res = perf_file_->WriteFully(str.c_str(), str.size());
227      CHECK(res);
228    }
229  }
230
231  // Trim maps to reduce memory usage.
232  // TODO: move this to an idle phase.
233  {
234    TimingLogger::ScopedTiming t2("TrimMaps", &logger);
235    runtime->GetJitArenaPool()->TrimMaps();
236  }
237
238  runtime->GetJit()->AddTimingLogger(logger);
239  return success;
240}
241
242}  // namespace jit
243}  // namespace art
244