• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "android-base/stringprintf.h"
20 
21 #include "arch/instruction_set.h"
22 #include "arch/instruction_set_features.h"
23 #include "art_method-inl.h"
24 #include "base/logging.h"  // For VLOG
25 #include "base/string_view_cpp20.h"
26 #include "base/systrace.h"
27 #include "base/time_utils.h"
28 #include "base/timing_logger.h"
29 #include "compiler.h"
30 #include "debug/elf_debug_writer.h"
31 #include "driver/compiler_options.h"
32 #include "jit/debugger_interface.h"
33 #include "jit/jit.h"
34 #include "jit/jit_code_cache.h"
35 #include "jit/jit_logger.h"
36 
37 namespace art HIDDEN {
38 namespace jit {
39 
Create()40 JitCompiler* JitCompiler::Create() {
41   return new JitCompiler();
42 }
43 
SetDebuggableCompilerOption(bool value)44 void JitCompiler::SetDebuggableCompilerOption(bool value) {
45   compiler_options_->SetDebuggable(value);
46 }
47 
ParseCompilerOptions()48 void JitCompiler::ParseCompilerOptions() {
49   // Special case max code units for inlining, whose default is "unset" (implictly
50   // meaning no limit). Do this before parsing the actual passed options.
51   compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
52   Runtime* runtime = Runtime::Current();
53   {
54     std::string error_msg;
55     if (!compiler_options_->ParseCompilerOptions(runtime->GetCompilerOptions(),
56                                                 /*ignore_unrecognized=*/ true,
57                                                 &error_msg)) {
58       LOG(FATAL) << error_msg;
59       UNREACHABLE();
60     }
61   }
62   // Set to appropriate JIT compiler type.
63   compiler_options_->compiler_type_ = runtime->IsZygote()
64       ? CompilerOptions::CompilerType::kSharedCodeJitCompiler
65       : CompilerOptions::CompilerType::kJitCompiler;
66   // JIT is never PIC, no matter what the runtime compiler options specify.
67   compiler_options_->SetNonPic();
68 
69   // If the options don't provide whether we generate debuggable code, set
70   // debuggability based on the runtime value.
71   if (!compiler_options_->GetDebuggable()) {
72     compiler_options_->SetDebuggable(runtime->IsJavaDebuggable());
73   }
74 
75   compiler_options_->implicit_null_checks_ = runtime->GetImplicitNullChecks();
76   compiler_options_->implicit_so_checks_ = runtime->GetImplicitStackOverflowChecks();
77   compiler_options_->implicit_suspend_checks_ = runtime->GetImplicitSuspendChecks();
78 
79   const InstructionSet instruction_set = compiler_options_->GetInstructionSet();
80   if (kRuntimeISA == InstructionSet::kArm) {
81     DCHECK_EQ(instruction_set, InstructionSet::kThumb2);
82   } else {
83     DCHECK_EQ(instruction_set, kRuntimeISA);
84   }
85   std::unique_ptr<const InstructionSetFeatures> instruction_set_features;
86   for (const std::string& option : runtime->GetCompilerOptions()) {
87     VLOG(compiler) << "JIT compiler option " << option;
88     std::string error_msg;
89     if (StartsWith(option, "--instruction-set-variant=")) {
90       const char* str = option.c_str() + strlen("--instruction-set-variant=");
91       VLOG(compiler) << "JIT instruction set variant " << str;
92       instruction_set_features = InstructionSetFeatures::FromVariantAndHwcap(
93           instruction_set, str, &error_msg);
94       if (instruction_set_features == nullptr) {
95         LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
96       }
97     } else if (StartsWith(option, "--instruction-set-features=")) {
98       const char* str = option.c_str() + strlen("--instruction-set-features=");
99       VLOG(compiler) << "JIT instruction set features " << str;
100       if (instruction_set_features == nullptr) {
101         instruction_set_features = InstructionSetFeatures::FromVariant(
102             instruction_set, "default", &error_msg);
103         if (instruction_set_features == nullptr) {
104           LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
105         }
106       }
107       instruction_set_features =
108           instruction_set_features->AddFeaturesFromString(str, &error_msg);
109       if (instruction_set_features == nullptr) {
110         LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
111       }
112     }
113   }
114 
115   if (instruction_set_features == nullptr) {
116     // '--instruction-set-features/--instruction-set-variant' were not used.
117     // Use build-time defined features.
118     instruction_set_features = InstructionSetFeatures::FromCppDefines();
119   }
120   compiler_options_->instruction_set_features_ = std::move(instruction_set_features);
121 
122   if (compiler_options_->GetGenerateDebugInfo()) {
123     jit_logger_.reset(new JitLogger());
124     jit_logger_->OpenLog();
125   }
126 }
127 
jit_load()128 EXPORT extern "C" JitCompilerInterface* jit_load() {
129   VLOG(jit) << "Create jit compiler";
130   auto* const jit_compiler = JitCompiler::Create();
131   CHECK(jit_compiler != nullptr);
132   VLOG(jit) << "Done creating jit compiler";
133   return jit_compiler;
134 }
135 
TypesLoaded(mirror::Class ** types,size_t count)136 void JitCompiler::TypesLoaded(mirror::Class** types, size_t count) {
137   const CompilerOptions& compiler_options = GetCompilerOptions();
138   if (compiler_options.GetGenerateDebugInfo()) {
139     InstructionSet isa = compiler_options.GetInstructionSet();
140     const InstructionSetFeatures* features = compiler_options.GetInstructionSetFeatures();
141     const ArrayRef<mirror::Class*> types_array(types, count);
142     std::vector<uint8_t> elf_file =
143         debug::WriteDebugElfFileForClasses(isa, features, types_array);
144 
145     // NB: Don't allow packing since it would remove non-backtrace data.
146     MutexLock mu(Thread::Current(), *Locks::jit_lock_);
147     AddNativeDebugInfoForJit(/*code_ptr=*/ nullptr, elf_file, /*allow_packing=*/ false);
148   }
149 }
150 
GenerateDebugInfo()151 bool JitCompiler::GenerateDebugInfo() {
152   return GetCompilerOptions().GetGenerateDebugInfo();
153 }
154 
PackElfFileForJIT(ArrayRef<const JITCodeEntry * > elf_files,ArrayRef<const void * > removed_symbols,bool compress,size_t * num_symbols)155 std::vector<uint8_t> JitCompiler::PackElfFileForJIT(ArrayRef<const JITCodeEntry*> elf_files,
156                                                     ArrayRef<const void*> removed_symbols,
157                                                     bool compress,
158                                                     /*out*/ size_t* num_symbols) {
159   return debug::PackElfFileForJIT(elf_files, removed_symbols, compress, num_symbols);
160 }
161 
JitCompiler()162 JitCompiler::JitCompiler() {
163   compiler_options_.reset(new CompilerOptions());
164   ParseCompilerOptions();
165   compiler_.reset(
166       Compiler::Create(*compiler_options_, /*storage=*/ nullptr, Compiler::kOptimizing));
167 }
168 
~JitCompiler()169 JitCompiler::~JitCompiler() {
170   if (compiler_options_->GetGenerateDebugInfo()) {
171     jit_logger_->CloseLog();
172   }
173 }
174 
CompileMethod(Thread * self,JitMemoryRegion * region,ArtMethod * method,CompilationKind compilation_kind)175 bool JitCompiler::CompileMethod(
176     Thread* self, JitMemoryRegion* region, ArtMethod* method, CompilationKind compilation_kind) {
177   SCOPED_TRACE << "JIT compiling "
178                << method->PrettyMethod()
179                << " (kind=" << compilation_kind << ")";
180 
181   DCHECK(!method->IsProxyMethod());
182   DCHECK(method->GetDeclaringClass()->IsResolved());
183 
184   TimingLogger logger(
185       "JIT compiler timing logger", true, VLOG_IS_ON(jit), TimingLogger::TimingKind::kThreadCpu);
186   self->AssertNoPendingException();
187   Runtime* runtime = Runtime::Current();
188 
189   // Do the compilation.
190   bool success = false;
191   {
192     TimingLogger::ScopedTiming t2(compilation_kind == CompilationKind::kOsr
193                                       ? "Compiling OSR"
194                                       : compilation_kind == CompilationKind::kOptimized
195                                           ? "Compiling optimized"
196                                           : "Compiling baseline",
197                                   &logger);
198     JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
199     metrics::AutoTimer timer{runtime->GetMetrics()->JitMethodCompileTotalTime()};
200     success = compiler_->JitCompile(
201         self, code_cache, region, method, compilation_kind, jit_logger_.get());
202     uint64_t duration_us = timer.Stop();
203     VLOG(jit) << "Compilation of " << method->PrettyMethod() << " took "
204               << PrettyDuration(UsToNs(duration_us));
205     runtime->GetMetrics()->JitMethodCompileCount()->AddOne();
206     runtime->GetMetrics()->JitMethodCompileTotalTimeDelta()->Add(duration_us);
207     runtime->GetMetrics()->JitMethodCompileCountDelta()->AddOne();
208   }
209 
210   // Trim maps to reduce memory usage.
211   // TODO: move this to an idle phase.
212   {
213     TimingLogger::ScopedTiming t2("TrimMaps", &logger);
214     runtime->GetJitArenaPool()->TrimMaps();
215   }
216 
217   runtime->GetJit()->AddTimingLogger(logger);
218   return success;
219 }
220 
IsBaselineCompiler() const221 bool JitCompiler::IsBaselineCompiler() const {
222   return compiler_options_->IsBaseline();
223 }
224 
225 }  // namespace jit
226 }  // namespace art
227