• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 "common_compiler_test.h"
18 
19 #include <android-base/unique_fd.h>
20 #include <type_traits>
21 
22 #include "arch/instruction_set_features.h"
23 #include "art_field-inl.h"
24 #include "art_method-inl.h"
25 #include "base/callee_save_type.h"
26 #include "base/casts.h"
27 #include "base/enums.h"
28 #include "base/memfd.h"
29 #include "base/utils.h"
30 #include "class_linker.h"
31 #include "compiled_method-inl.h"
32 #include "dex/descriptors_names.h"
33 #include "dex/verification_results.h"
34 #include "driver/compiled_method_storage.h"
35 #include "driver/compiler_options.h"
36 #include "jni/java_vm_ext.h"
37 #include "interpreter/interpreter.h"
38 #include "mirror/class-inl.h"
39 #include "mirror/class_loader.h"
40 #include "mirror/dex_cache.h"
41 #include "mirror/object-inl.h"
42 #include "oat_quick_method_header.h"
43 #include "scoped_thread_state_change-inl.h"
44 #include "thread-current-inl.h"
45 #include "utils/atomic_dex_ref_map-inl.h"
46 
47 namespace art {
48 
49 class CommonCompilerTestImpl::CodeAndMetadata {
50  public:
51   CodeAndMetadata(CodeAndMetadata&& other) = default;
52 
CodeAndMetadata(ArrayRef<const uint8_t> code,ArrayRef<const uint8_t> vmap_table,InstructionSet instruction_set)53   CodeAndMetadata(ArrayRef<const uint8_t> code,
54                   ArrayRef<const uint8_t> vmap_table,
55                   InstructionSet instruction_set) {
56     const uint32_t code_size = code.size();
57     CHECK_NE(code_size, 0u);
58     const uint32_t vmap_table_offset = vmap_table.empty() ? 0u
59         : sizeof(OatQuickMethodHeader) + vmap_table.size();
60     OatQuickMethodHeader method_header(vmap_table_offset);
61     const size_t code_alignment = GetInstructionSetAlignment(instruction_set);
62     DCHECK_ALIGNED_PARAM(kPageSize, code_alignment);
63     code_offset_ = RoundUp(vmap_table.size() + sizeof(method_header), code_alignment);
64     const uint32_t capacity = RoundUp(code_offset_ + code_size, kPageSize);
65 
66     // Create a memfd handle with sufficient capacity.
67     android::base::unique_fd mem_fd(art::memfd_create_compat("test code", /*flags=*/ 0));
68     CHECK_GE(mem_fd.get(), 0);
69     int err = ftruncate(mem_fd, capacity);
70     CHECK_EQ(err, 0);
71 
72     // Map the memfd contents for read/write.
73     std::string error_msg;
74     rw_map_ = MemMap::MapFile(capacity,
75                               PROT_READ | PROT_WRITE,
76                               MAP_SHARED,
77                               mem_fd,
78                               /*start=*/ 0,
79                               /*low_4gb=*/ false,
80                               /*filename=*/ "test code",
81                               &error_msg);
82     CHECK(rw_map_.IsValid()) << error_msg;
83 
84     // Store data.
85     uint8_t* code_addr = rw_map_.Begin() + code_offset_;
86     CHECK_ALIGNED_PARAM(code_addr, code_alignment);
87     CHECK_LE(vmap_table_offset, code_offset_);
88     memcpy(code_addr - vmap_table_offset, vmap_table.data(), vmap_table.size());
89     static_assert(std::is_trivially_copyable<OatQuickMethodHeader>::value, "Cannot use memcpy");
90     CHECK_LE(sizeof(method_header), code_offset_);
91     memcpy(code_addr - sizeof(method_header), &method_header, sizeof(method_header));
92     CHECK_LE(code_size, static_cast<size_t>(rw_map_.End() - code_addr));
93     memcpy(code_addr, code.data(), code_size);
94 
95     // Sync data.
96     bool success = rw_map_.Sync();
97     CHECK(success);
98     success = FlushCpuCaches(rw_map_.Begin(), rw_map_.End());
99     CHECK(success);
100 
101     // Map the data as read/executable.
102     rx_map_ = MemMap::MapFile(capacity,
103                               PROT_READ | PROT_EXEC,
104                               MAP_SHARED,
105                               mem_fd,
106                               /*start=*/ 0,
107                               /*low_4gb=*/ false,
108                               /*filename=*/ "test code",
109                               &error_msg);
110     CHECK(rx_map_.IsValid()) << error_msg;
111   }
112 
GetCodePointer() const113   const void* GetCodePointer() const {
114     DCHECK(rx_map_.IsValid());
115     DCHECK_LE(code_offset_, rx_map_.Size());
116     return rx_map_.Begin() + code_offset_;
117   }
118 
119  private:
120   MemMap rw_map_;
121   MemMap rx_map_;
122   uint32_t code_offset_;
123 
124   DISALLOW_COPY_AND_ASSIGN(CodeAndMetadata);
125 };
126 
CreateCompilerOptions(InstructionSet instruction_set,const std::string & variant)127 std::unique_ptr<CompilerOptions> CommonCompilerTestImpl::CreateCompilerOptions(
128     InstructionSet instruction_set, const std::string& variant) {
129   std::unique_ptr<CompilerOptions> compiler_options = std::make_unique<CompilerOptions>();
130   compiler_options->instruction_set_ = instruction_set;
131   std::string error_msg;
132   compiler_options->instruction_set_features_ =
133       InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
134   CHECK(compiler_options->instruction_set_features_ != nullptr) << error_msg;
135   return compiler_options;
136 }
137 
CommonCompilerTestImpl()138 CommonCompilerTestImpl::CommonCompilerTestImpl() {}
~CommonCompilerTestImpl()139 CommonCompilerTestImpl::~CommonCompilerTestImpl() {}
140 
MakeExecutable(ArrayRef<const uint8_t> code,ArrayRef<const uint8_t> vmap_table,InstructionSet instruction_set)141 const void* CommonCompilerTestImpl::MakeExecutable(ArrayRef<const uint8_t> code,
142                                                    ArrayRef<const uint8_t> vmap_table,
143                                                    InstructionSet instruction_set) {
144   CHECK_NE(code.size(), 0u);
145   code_and_metadata_.emplace_back(code, vmap_table, instruction_set);
146   return code_and_metadata_.back().GetCodePointer();
147 }
148 
MakeExecutable(ArtMethod * method,const CompiledMethod * compiled_method)149 void CommonCompilerTestImpl::MakeExecutable(ArtMethod* method,
150                                             const CompiledMethod* compiled_method) {
151   CHECK(method != nullptr);
152   // If the code size is 0 it means the method was skipped due to profile guided compilation.
153   if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0u) {
154     const void* code_ptr = MakeExecutable(compiled_method->GetQuickCode(),
155                                           compiled_method->GetVmapTable(),
156                                           compiled_method->GetInstructionSet());
157     const void* method_code =
158         CompiledMethod::CodePointer(code_ptr, compiled_method->GetInstructionSet());
159     LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
160     method->SetEntryPointFromQuickCompiledCode(method_code);
161   } else {
162     // No code? You must mean to go into the interpreter.
163     // Or the generic JNI...
164     GetClassLinker()->SetEntryPointsToInterpreter(method);
165   }
166 }
167 
SetUp()168 void CommonCompilerTestImpl::SetUp() {
169   {
170     ScopedObjectAccess soa(Thread::Current());
171 
172     Runtime* runtime = GetRuntime();
173     runtime->SetInstructionSet(instruction_set_);
174     for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) {
175       CalleeSaveType type = CalleeSaveType(i);
176       if (!runtime->HasCalleeSaveMethod(type)) {
177         runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(), type);
178       }
179     }
180   }
181 }
182 
ApplyInstructionSet()183 void CommonCompilerTestImpl::ApplyInstructionSet() {
184   // Copy local instruction_set_ and instruction_set_features_ to *compiler_options_;
185   CHECK(instruction_set_features_ != nullptr);
186   if (instruction_set_ == InstructionSet::kThumb2) {
187     CHECK_EQ(InstructionSet::kArm, instruction_set_features_->GetInstructionSet());
188   } else {
189     CHECK_EQ(instruction_set_, instruction_set_features_->GetInstructionSet());
190   }
191   compiler_options_->instruction_set_ = instruction_set_;
192   compiler_options_->instruction_set_features_ =
193       InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap());
194   CHECK(compiler_options_->instruction_set_features_->Equals(instruction_set_features_.get()));
195 }
196 
OverrideInstructionSetFeatures(InstructionSet instruction_set,const std::string & variant)197 void CommonCompilerTestImpl::OverrideInstructionSetFeatures(InstructionSet instruction_set,
198                                                             const std::string& variant) {
199   instruction_set_ = instruction_set;
200   std::string error_msg;
201   instruction_set_features_ =
202       InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
203   CHECK(instruction_set_features_ != nullptr) << error_msg;
204 
205   if (compiler_options_ != nullptr) {
206     ApplyInstructionSet();
207   }
208 }
209 
SetUpRuntimeOptionsImpl()210 void CommonCompilerTestImpl::SetUpRuntimeOptionsImpl() {
211   compiler_options_.reset(new CompilerOptions);
212   verification_results_.reset(new VerificationResults(compiler_options_.get()));
213 
214   ApplyInstructionSet();
215 }
216 
GetCompilerKind() const217 Compiler::Kind CommonCompilerTestImpl::GetCompilerKind() const {
218   return compiler_kind_;
219 }
220 
SetCompilerKind(Compiler::Kind compiler_kind)221 void CommonCompilerTestImpl::SetCompilerKind(Compiler::Kind compiler_kind) {
222   compiler_kind_ = compiler_kind;
223 }
224 
TearDown()225 void CommonCompilerTestImpl::TearDown() {
226   code_and_metadata_.clear();
227   verification_results_.reset();
228   compiler_options_.reset();
229 }
230 
CompileMethod(ArtMethod * method)231 void CommonCompilerTestImpl::CompileMethod(ArtMethod* method) {
232   CHECK(method != nullptr);
233   TimingLogger timings("CommonCompilerTestImpl::CompileMethod", false, false);
234   TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
235   CompiledMethodStorage storage(/*swap_fd=*/ -1);
236   CompiledMethod* compiled_method = nullptr;
237   {
238     DCHECK(!Runtime::Current()->IsStarted());
239     Thread* self = Thread::Current();
240     StackHandleScope<2> hs(self);
241     std::unique_ptr<Compiler> compiler(
242         Compiler::Create(*compiler_options_, &storage, compiler_kind_));
243     const DexFile& dex_file = *method->GetDexFile();
244     Handle<mirror::DexCache> dex_cache =
245         hs.NewHandle(GetClassLinker()->FindDexCache(self, dex_file));
246     Handle<mirror::ClassLoader> class_loader = hs.NewHandle(method->GetClassLoader());
247     compiler_options_->verification_results_ = verification_results_.get();
248     if (method->IsNative()) {
249       compiled_method = compiler->JniCompile(method->GetAccessFlags(),
250                                              method->GetDexMethodIndex(),
251                                              dex_file,
252                                              dex_cache);
253     } else {
254       verification_results_->AddDexFile(&dex_file);
255       verification_results_->CreateVerifiedMethodFor(
256           MethodReference(&dex_file, method->GetDexMethodIndex()));
257       compiled_method = compiler->Compile(method->GetCodeItem(),
258                                           method->GetAccessFlags(),
259                                           method->GetInvokeType(),
260                                           method->GetClassDefIndex(),
261                                           method->GetDexMethodIndex(),
262                                           class_loader,
263                                           dex_file,
264                                           dex_cache);
265     }
266     compiler_options_->verification_results_ = nullptr;
267   }
268   CHECK(method != nullptr);
269   {
270     TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
271     MakeExecutable(method, compiled_method);
272   }
273   CompiledMethod::ReleaseSwapAllocatedCompiledMethod(&storage, compiled_method);
274 }
275 
CompileDirectMethod(Handle<mirror::ClassLoader> class_loader,const char * class_name,const char * method_name,const char * signature)276 void CommonCompilerTestImpl::CompileDirectMethod(Handle<mirror::ClassLoader> class_loader,
277                                                  const char* class_name,
278                                                  const char* method_name,
279                                                  const char* signature) {
280   std::string class_descriptor(DotToDescriptor(class_name));
281   Thread* self = Thread::Current();
282   ClassLinker* class_linker = GetClassLinker();
283   ObjPtr<mirror::Class> klass =
284       class_linker->FindClass(self, class_descriptor.c_str(), class_loader);
285   CHECK(klass != nullptr) << "Class not found " << class_name;
286   auto pointer_size = class_linker->GetImagePointerSize();
287   ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size);
288   CHECK(method != nullptr && method->IsDirect()) << "Direct method not found: "
289       << class_name << "." << method_name << signature;
290   CompileMethod(method);
291 }
292 
CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader,const char * class_name,const char * method_name,const char * signature)293 void CommonCompilerTestImpl::CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader,
294                                                   const char* class_name,
295                                                   const char* method_name,
296                                                   const char* signature) {
297   std::string class_descriptor(DotToDescriptor(class_name));
298   Thread* self = Thread::Current();
299   ClassLinker* class_linker = GetClassLinker();
300   ObjPtr<mirror::Class> klass =
301       class_linker->FindClass(self, class_descriptor.c_str(), class_loader);
302   CHECK(klass != nullptr) << "Class not found " << class_name;
303   auto pointer_size = class_linker->GetImagePointerSize();
304   ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size);
305   CHECK(method != nullptr && !method->IsDirect()) << "Virtual method not found: "
306       << class_name << "." << method_name << signature;
307   CompileMethod(method);
308 }
309 
ClearBootImageOption()310 void CommonCompilerTestImpl::ClearBootImageOption() {
311   compiler_options_->image_type_ = CompilerOptions::ImageType::kNone;
312 }
313 
314 }  // namespace art
315