• 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   const void* method_code = nullptr;
153   // If the code size is 0 it means the method was skipped due to profile guided compilation.
154   if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0u) {
155     const void* code_ptr = MakeExecutable(compiled_method->GetQuickCode(),
156                                           compiled_method->GetVmapTable(),
157                                           compiled_method->GetInstructionSet());
158     method_code =
159         CompiledMethod::CodePointer(code_ptr, compiled_method->GetInstructionSet());
160     LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
161   }
162   Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(
163       method, /*aot_code=*/ method_code);
164 }
165 
SetUp()166 void CommonCompilerTestImpl::SetUp() {
167   {
168     ScopedObjectAccess soa(Thread::Current());
169 
170     Runtime* runtime = GetRuntime();
171     runtime->SetInstructionSet(instruction_set_);
172     for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) {
173       CalleeSaveType type = CalleeSaveType(i);
174       if (!runtime->HasCalleeSaveMethod(type)) {
175         runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(), type);
176       }
177     }
178   }
179 }
180 
ApplyInstructionSet()181 void CommonCompilerTestImpl::ApplyInstructionSet() {
182   // Copy local instruction_set_ and instruction_set_features_ to *compiler_options_;
183   CHECK(instruction_set_features_ != nullptr);
184   if (instruction_set_ == InstructionSet::kThumb2) {
185     CHECK_EQ(InstructionSet::kArm, instruction_set_features_->GetInstructionSet());
186   } else {
187     CHECK_EQ(instruction_set_, instruction_set_features_->GetInstructionSet());
188   }
189   compiler_options_->instruction_set_ = instruction_set_;
190   compiler_options_->instruction_set_features_ =
191       InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap());
192   CHECK(compiler_options_->instruction_set_features_->Equals(instruction_set_features_.get()));
193 }
194 
OverrideInstructionSetFeatures(InstructionSet instruction_set,const std::string & variant)195 void CommonCompilerTestImpl::OverrideInstructionSetFeatures(InstructionSet instruction_set,
196                                                             const std::string& variant) {
197   instruction_set_ = instruction_set;
198   std::string error_msg;
199   instruction_set_features_ =
200       InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
201   CHECK(instruction_set_features_ != nullptr) << error_msg;
202 
203   if (compiler_options_ != nullptr) {
204     ApplyInstructionSet();
205   }
206 }
207 
SetUpRuntimeOptionsImpl()208 void CommonCompilerTestImpl::SetUpRuntimeOptionsImpl() {
209   compiler_options_.reset(new CompilerOptions);
210   verification_results_.reset(new VerificationResults());
211   ApplyInstructionSet();
212 }
213 
GetCompilerKind() const214 Compiler::Kind CommonCompilerTestImpl::GetCompilerKind() const {
215   return compiler_kind_;
216 }
217 
SetCompilerKind(Compiler::Kind compiler_kind)218 void CommonCompilerTestImpl::SetCompilerKind(Compiler::Kind compiler_kind) {
219   compiler_kind_ = compiler_kind;
220 }
221 
TearDown()222 void CommonCompilerTestImpl::TearDown() {
223   code_and_metadata_.clear();
224   verification_results_.reset();
225   compiler_options_.reset();
226 }
227 
CompileMethod(ArtMethod * method)228 void CommonCompilerTestImpl::CompileMethod(ArtMethod* method) {
229   CHECK(method != nullptr);
230   TimingLogger timings("CommonCompilerTestImpl::CompileMethod", false, false);
231   TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
232   CompiledMethodStorage storage(/*swap_fd=*/ -1);
233   CompiledMethod* compiled_method = nullptr;
234   {
235     DCHECK(!Runtime::Current()->IsStarted());
236     Thread* self = Thread::Current();
237     StackHandleScope<2> hs(self);
238     std::unique_ptr<Compiler> compiler(
239         Compiler::Create(*compiler_options_, &storage, compiler_kind_));
240     const DexFile& dex_file = *method->GetDexFile();
241     Handle<mirror::DexCache> dex_cache =
242         hs.NewHandle(GetClassLinker()->FindDexCache(self, dex_file));
243     Handle<mirror::ClassLoader> class_loader = hs.NewHandle(method->GetClassLoader());
244     compiler_options_->verification_results_ = verification_results_.get();
245     if (method->IsNative()) {
246       compiled_method = compiler->JniCompile(method->GetAccessFlags(),
247                                              method->GetDexMethodIndex(),
248                                              dex_file,
249                                              dex_cache);
250     } else {
251       compiled_method = compiler->Compile(method->GetCodeItem(),
252                                           method->GetAccessFlags(),
253                                           method->GetInvokeType(),
254                                           method->GetClassDefIndex(),
255                                           method->GetDexMethodIndex(),
256                                           class_loader,
257                                           dex_file,
258                                           dex_cache);
259     }
260     compiler_options_->verification_results_ = nullptr;
261   }
262   CHECK(method != nullptr);
263   {
264     TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
265     MakeExecutable(method, compiled_method);
266   }
267   CompiledMethod::ReleaseSwapAllocatedCompiledMethod(&storage, compiled_method);
268 }
269 
CompileDirectMethod(Handle<mirror::ClassLoader> class_loader,const char * class_name,const char * method_name,const char * signature)270 void CommonCompilerTestImpl::CompileDirectMethod(Handle<mirror::ClassLoader> class_loader,
271                                                  const char* class_name,
272                                                  const char* method_name,
273                                                  const char* signature) {
274   std::string class_descriptor(DotToDescriptor(class_name));
275   Thread* self = Thread::Current();
276   ClassLinker* class_linker = GetClassLinker();
277   ObjPtr<mirror::Class> klass =
278       class_linker->FindClass(self, class_descriptor.c_str(), class_loader);
279   CHECK(klass != nullptr) << "Class not found " << class_name;
280   auto pointer_size = class_linker->GetImagePointerSize();
281   ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size);
282   CHECK(method != nullptr && method->IsDirect()) << "Direct method not found: "
283       << class_name << "." << method_name << signature;
284   CompileMethod(method);
285 }
286 
CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader,const char * class_name,const char * method_name,const char * signature)287 void CommonCompilerTestImpl::CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader,
288                                                   const char* class_name,
289                                                   const char* method_name,
290                                                   const char* signature) {
291   std::string class_descriptor(DotToDescriptor(class_name));
292   Thread* self = Thread::Current();
293   ClassLinker* class_linker = GetClassLinker();
294   ObjPtr<mirror::Class> klass =
295       class_linker->FindClass(self, class_descriptor.c_str(), class_loader);
296   CHECK(klass != nullptr) << "Class not found " << class_name;
297   auto pointer_size = class_linker->GetImagePointerSize();
298   ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size);
299   CHECK(method != nullptr && !method->IsDirect()) << "Virtual method not found: "
300       << class_name << "." << method_name << signature;
301   CompileMethod(method);
302 }
303 
ClearBootImageOption()304 void CommonCompilerTestImpl::ClearBootImageOption() {
305   compiler_options_->image_type_ = CompilerOptions::ImageType::kNone;
306 }
307 
308 }  // namespace art
309