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 "dex/descriptors_names.h"
32 #include "driver/compiled_code_storage.h"
33 #include "driver/compiler_options.h"
34 #include "jni/java_vm_ext.h"
35 #include "interpreter/interpreter.h"
36 #include "mirror/class-inl.h"
37 #include "mirror/class_loader.h"
38 #include "mirror/dex_cache.h"
39 #include "mirror/object-inl.h"
40 #include "oat_quick_method_header.h"
41 #include "scoped_thread_state_change-inl.h"
42 #include "thread-current-inl.h"
43 #include "utils/atomic_dex_ref_map-inl.h"
44
45 namespace art HIDDEN {
46
47 class CommonCompilerTestImpl::CodeAndMetadata {
48 public:
49 CodeAndMetadata(CodeAndMetadata&& other) = default;
50
CodeAndMetadata(ArrayRef<const uint8_t> code,ArrayRef<const uint8_t> vmap_table,InstructionSet instruction_set)51 CodeAndMetadata(ArrayRef<const uint8_t> code,
52 ArrayRef<const uint8_t> vmap_table,
53 InstructionSet instruction_set) {
54 const uint32_t code_size = code.size();
55 CHECK_NE(code_size, 0u);
56 const uint32_t vmap_table_offset = vmap_table.empty() ? 0u
57 : sizeof(OatQuickMethodHeader) + vmap_table.size();
58 OatQuickMethodHeader method_header(vmap_table_offset);
59 const size_t code_alignment = GetInstructionSetCodeAlignment(instruction_set);
60 DCHECK_ALIGNED_PARAM(kPageSize, code_alignment);
61 const uint32_t code_offset = RoundUp(vmap_table.size() + sizeof(method_header), code_alignment);
62 const uint32_t capacity = RoundUp(code_offset + code_size, kPageSize);
63
64 // Create a memfd handle with sufficient capacity.
65 android::base::unique_fd mem_fd(art::memfd_create_compat("test code", /*flags=*/ 0));
66 CHECK_GE(mem_fd.get(), 0);
67 int err = ftruncate(mem_fd, capacity);
68 CHECK_EQ(err, 0);
69
70 // Map the memfd contents for read/write.
71 std::string error_msg;
72 rw_map_ = MemMap::MapFile(capacity,
73 PROT_READ | PROT_WRITE,
74 MAP_SHARED,
75 mem_fd,
76 /*start=*/ 0,
77 /*low_4gb=*/ false,
78 /*filename=*/ "test code",
79 &error_msg);
80 CHECK(rw_map_.IsValid()) << error_msg;
81
82 // Store data.
83 uint8_t* code_addr = rw_map_.Begin() + code_offset;
84 CHECK_ALIGNED_PARAM(code_addr, code_alignment);
85 CHECK_LE(vmap_table_offset, code_offset);
86 memcpy(code_addr - vmap_table_offset, vmap_table.data(), vmap_table.size());
87 static_assert(std::is_trivially_copyable<OatQuickMethodHeader>::value, "Cannot use memcpy");
88 CHECK_LE(sizeof(method_header), code_offset);
89 memcpy(code_addr - sizeof(method_header), &method_header, sizeof(method_header));
90 CHECK_LE(code_size, static_cast<size_t>(rw_map_.End() - code_addr));
91 memcpy(code_addr, code.data(), code_size);
92
93 // Sync data.
94 bool success = rw_map_.Sync();
95 CHECK(success);
96 success = FlushCpuCaches(rw_map_.Begin(), rw_map_.End());
97 CHECK(success);
98
99 // Map the data as read/executable.
100 rx_map_ = MemMap::MapFile(capacity,
101 PROT_READ | PROT_EXEC,
102 MAP_SHARED,
103 mem_fd,
104 /*start=*/ 0,
105 /*low_4gb=*/ false,
106 /*filename=*/ "test code",
107 &error_msg);
108 CHECK(rx_map_.IsValid()) << error_msg;
109
110 DCHECK_LT(code_offset, rx_map_.Size());
111 size_t adjustment = GetInstructionSetEntryPointAdjustment(instruction_set);
112 entry_point_ = rx_map_.Begin() + code_offset + adjustment;
113 }
114
GetEntryPoint() const115 const void* GetEntryPoint() const {
116 DCHECK(rx_map_.IsValid());
117 return entry_point_;
118 }
119
120 private:
121 MemMap rw_map_;
122 MemMap rx_map_;
123 const void* entry_point_;
124
125 DISALLOW_COPY_AND_ASSIGN(CodeAndMetadata);
126 };
127
128 class CommonCompilerTestImpl::OneCompiledMethodStorage final : public CompiledCodeStorage {
129 public:
OneCompiledMethodStorage()130 OneCompiledMethodStorage() {}
~OneCompiledMethodStorage()131 ~OneCompiledMethodStorage() {}
132
CreateCompiledMethod(InstructionSet instruction_set,ArrayRef<const uint8_t> code,ArrayRef<const uint8_t> stack_map,ArrayRef<const uint8_t> cfi ATTRIBUTE_UNUSED,ArrayRef<const linker::LinkerPatch> patches,bool is_intrinsic ATTRIBUTE_UNUSED)133 CompiledMethod* CreateCompiledMethod(InstructionSet instruction_set,
134 ArrayRef<const uint8_t> code,
135 ArrayRef<const uint8_t> stack_map,
136 ArrayRef<const uint8_t> cfi ATTRIBUTE_UNUSED,
137 ArrayRef<const linker::LinkerPatch> patches,
138 bool is_intrinsic ATTRIBUTE_UNUSED) override {
139 // Supports only one method at a time.
140 CHECK_EQ(instruction_set_, InstructionSet::kNone);
141 CHECK_NE(instruction_set, InstructionSet::kNone);
142 instruction_set_ = instruction_set;
143 CHECK(code_.empty());
144 CHECK(!code.empty());
145 code_.assign(code.begin(), code.end());
146 CHECK(stack_map_.empty());
147 CHECK(!stack_map.empty());
148 stack_map_.assign(stack_map.begin(), stack_map.end());
149 CHECK(patches.empty()) << "Linker patches are unsupported for compiler gtests.";
150 return reinterpret_cast<CompiledMethod*>(this);
151 }
152
GetThunkCode(const linker::LinkerPatch & patch ATTRIBUTE_UNUSED,std::string * debug_name ATTRIBUTE_UNUSED)153 ArrayRef<const uint8_t> GetThunkCode(const linker::LinkerPatch& patch ATTRIBUTE_UNUSED,
154 /*out*/ std::string* debug_name ATTRIBUTE_UNUSED) override {
155 LOG(FATAL) << "Unsupported.";
156 UNREACHABLE();
157 }
158
SetThunkCode(const linker::LinkerPatch & patch ATTRIBUTE_UNUSED,ArrayRef<const uint8_t> code ATTRIBUTE_UNUSED,const std::string & debug_name ATTRIBUTE_UNUSED)159 void SetThunkCode(const linker::LinkerPatch& patch ATTRIBUTE_UNUSED,
160 ArrayRef<const uint8_t> code ATTRIBUTE_UNUSED,
161 const std::string& debug_name ATTRIBUTE_UNUSED) override {
162 LOG(FATAL) << "Unsupported.";
163 UNREACHABLE();
164 }
165
GetInstructionSet() const166 InstructionSet GetInstructionSet() const {
167 CHECK_NE(instruction_set_, InstructionSet::kNone);
168 return instruction_set_;
169 }
170
GetCode() const171 ArrayRef<const uint8_t> GetCode() const {
172 CHECK(!code_.empty());
173 return ArrayRef<const uint8_t>(code_);
174 }
175
GetStackMap() const176 ArrayRef<const uint8_t> GetStackMap() const {
177 CHECK(!stack_map_.empty());
178 return ArrayRef<const uint8_t>(stack_map_);
179 }
180
181 private:
182 InstructionSet instruction_set_ = InstructionSet::kNone;
183 std::vector<uint8_t> code_;
184 std::vector<uint8_t> stack_map_;
185 };
186
CreateCompilerOptions(InstructionSet instruction_set,const std::string & variant)187 std::unique_ptr<CompilerOptions> CommonCompilerTestImpl::CreateCompilerOptions(
188 InstructionSet instruction_set, const std::string& variant) {
189 std::unique_ptr<CompilerOptions> compiler_options = std::make_unique<CompilerOptions>();
190 compiler_options->instruction_set_ = instruction_set;
191 std::string error_msg;
192 compiler_options->instruction_set_features_ =
193 InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
194 CHECK(compiler_options->instruction_set_features_ != nullptr) << error_msg;
195 return compiler_options;
196 }
197
CommonCompilerTestImpl()198 CommonCompilerTestImpl::CommonCompilerTestImpl() {}
~CommonCompilerTestImpl()199 CommonCompilerTestImpl::~CommonCompilerTestImpl() {}
200
MakeExecutable(ArrayRef<const uint8_t> code,ArrayRef<const uint8_t> vmap_table,InstructionSet instruction_set)201 const void* CommonCompilerTestImpl::MakeExecutable(ArrayRef<const uint8_t> code,
202 ArrayRef<const uint8_t> vmap_table,
203 InstructionSet instruction_set) {
204 CHECK_NE(code.size(), 0u);
205 code_and_metadata_.emplace_back(code, vmap_table, instruction_set);
206 return code_and_metadata_.back().GetEntryPoint();
207 }
208
SetUp()209 void CommonCompilerTestImpl::SetUp() {
210 {
211 ScopedObjectAccess soa(Thread::Current());
212
213 Runtime* runtime = GetRuntime();
214 runtime->SetInstructionSet(instruction_set_);
215 for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) {
216 CalleeSaveType type = CalleeSaveType(i);
217 if (!runtime->HasCalleeSaveMethod(type)) {
218 runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(), type);
219 }
220 }
221 }
222 }
223
ApplyInstructionSet()224 void CommonCompilerTestImpl::ApplyInstructionSet() {
225 // Copy local instruction_set_ and instruction_set_features_ to *compiler_options_;
226 CHECK(instruction_set_features_ != nullptr);
227 if (instruction_set_ == InstructionSet::kThumb2) {
228 CHECK_EQ(InstructionSet::kArm, instruction_set_features_->GetInstructionSet());
229 } else {
230 CHECK_EQ(instruction_set_, instruction_set_features_->GetInstructionSet());
231 }
232 compiler_options_->instruction_set_ = instruction_set_;
233 compiler_options_->instruction_set_features_ =
234 InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap());
235 CHECK(compiler_options_->instruction_set_features_->Equals(instruction_set_features_.get()));
236 }
237
OverrideInstructionSetFeatures(InstructionSet instruction_set,const std::string & variant)238 void CommonCompilerTestImpl::OverrideInstructionSetFeatures(InstructionSet instruction_set,
239 const std::string& variant) {
240 instruction_set_ = instruction_set;
241 std::string error_msg;
242 instruction_set_features_ =
243 InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
244 CHECK(instruction_set_features_ != nullptr) << error_msg;
245
246 if (compiler_options_ != nullptr) {
247 ApplyInstructionSet();
248 }
249 }
250
SetUpRuntimeOptionsImpl()251 void CommonCompilerTestImpl::SetUpRuntimeOptionsImpl() {
252 compiler_options_.reset(new CompilerOptions);
253 ApplyInstructionSet();
254 }
255
GetCompilerKind() const256 Compiler::Kind CommonCompilerTestImpl::GetCompilerKind() const {
257 return compiler_kind_;
258 }
259
SetCompilerKind(Compiler::Kind compiler_kind)260 void CommonCompilerTestImpl::SetCompilerKind(Compiler::Kind compiler_kind) {
261 compiler_kind_ = compiler_kind;
262 }
263
TearDown()264 void CommonCompilerTestImpl::TearDown() {
265 code_and_metadata_.clear();
266 compiler_options_.reset();
267 }
268
CompileMethod(ArtMethod * method)269 void CommonCompilerTestImpl::CompileMethod(ArtMethod* method) {
270 CHECK(method != nullptr);
271 TimingLogger timings("CommonCompilerTestImpl::CompileMethod", false, false);
272 TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
273 OneCompiledMethodStorage storage;
274 CompiledMethod* compiled_method = nullptr;
275 {
276 DCHECK(!Runtime::Current()->IsStarted());
277 Thread* self = Thread::Current();
278 StackHandleScope<2> hs(self);
279 std::unique_ptr<Compiler> compiler(
280 Compiler::Create(*compiler_options_, &storage, compiler_kind_));
281 const DexFile& dex_file = *method->GetDexFile();
282 Handle<mirror::DexCache> dex_cache =
283 hs.NewHandle(GetClassLinker()->FindDexCache(self, dex_file));
284 Handle<mirror::ClassLoader> class_loader = hs.NewHandle(method->GetClassLoader());
285 if (method->IsNative()) {
286 compiled_method = compiler->JniCompile(method->GetAccessFlags(),
287 method->GetDexMethodIndex(),
288 dex_file,
289 dex_cache);
290 } else {
291 compiled_method = compiler->Compile(method->GetCodeItem(),
292 method->GetAccessFlags(),
293 method->GetInvokeType(),
294 method->GetClassDefIndex(),
295 method->GetDexMethodIndex(),
296 class_loader,
297 dex_file,
298 dex_cache);
299 }
300 CHECK(compiled_method != nullptr) << "Failed to compile " << method->PrettyMethod();
301 CHECK_EQ(reinterpret_cast<OneCompiledMethodStorage*>(compiled_method), &storage);
302 }
303 {
304 TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
305 const void* method_code = MakeExecutable(storage.GetCode(),
306 storage.GetStackMap(),
307 storage.GetInstructionSet());
308 LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
309 GetRuntime()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ method_code);
310 }
311 }
312
ClearBootImageOption()313 void CommonCompilerTestImpl::ClearBootImageOption() {
314 compiler_options_->image_type_ = CompilerOptions::ImageType::kNone;
315 }
316
317 } // namespace art
318