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 <type_traits> 20 21 #include "arch/instruction_set_features.h" 22 #include "art_field-inl.h" 23 #include "art_method-inl.h" 24 #include "base/callee_save_type.h" 25 #include "base/casts.h" 26 #include "base/enums.h" 27 #include "base/utils.h" 28 #include "class_linker.h" 29 #include "compiled_method-inl.h" 30 #include "dex/descriptors_names.h" 31 #include "dex/verification_results.h" 32 #include "driver/compiled_method_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 { 46 47 CommonCompilerTest::CommonCompilerTest() {} 48 CommonCompilerTest::~CommonCompilerTest() {} 49 50 void CommonCompilerTest::MakeExecutable(ArtMethod* method, const CompiledMethod* compiled_method) { 51 CHECK(method != nullptr); 52 // If the code size is 0 it means the method was skipped due to profile guided compilation. 53 if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0u) { 54 ArrayRef<const uint8_t> code = compiled_method->GetQuickCode(); 55 const uint32_t code_size = code.size(); 56 ArrayRef<const uint8_t> vmap_table = compiled_method->GetVmapTable(); 57 const uint32_t vmap_table_offset = vmap_table.empty() ? 0u 58 : sizeof(OatQuickMethodHeader) + vmap_table.size(); 59 OatQuickMethodHeader method_header(vmap_table_offset, code_size); 60 61 header_code_and_maps_chunks_.push_back(std::vector<uint8_t>()); 62 std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back(); 63 const size_t max_padding = GetInstructionSetAlignment(compiled_method->GetInstructionSet()); 64 const size_t size = vmap_table.size() + sizeof(method_header) + code_size; 65 chunk->reserve(size + max_padding); 66 chunk->resize(sizeof(method_header)); 67 static_assert(std::is_trivially_copyable<OatQuickMethodHeader>::value, "Cannot use memcpy"); 68 memcpy(&(*chunk)[0], &method_header, sizeof(method_header)); 69 chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end()); 70 chunk->insert(chunk->end(), code.begin(), code.end()); 71 CHECK_EQ(chunk->size(), size); 72 const void* unaligned_code_ptr = chunk->data() + (size - code_size); 73 size_t offset = dchecked_integral_cast<size_t>(reinterpret_cast<uintptr_t>(unaligned_code_ptr)); 74 size_t padding = compiled_method->AlignCode(offset) - offset; 75 // Make sure no resizing takes place. 76 CHECK_GE(chunk->capacity(), chunk->size() + padding); 77 chunk->insert(chunk->begin(), padding, 0); 78 const void* code_ptr = reinterpret_cast<const uint8_t*>(unaligned_code_ptr) + padding; 79 CHECK_EQ(code_ptr, static_cast<const void*>(chunk->data() + (chunk->size() - code_size))); 80 MakeExecutable(code_ptr, code.size()); 81 const void* method_code = CompiledMethod::CodePointer(code_ptr, 82 compiled_method->GetInstructionSet()); 83 LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code; 84 method->SetEntryPointFromQuickCompiledCode(method_code); 85 } else { 86 // No code? You must mean to go into the interpreter. 87 // Or the generic JNI... 88 class_linker_->SetEntryPointsToInterpreter(method); 89 } 90 } 91 92 void CommonCompilerTest::MakeExecutable(const void* code_start, size_t code_length) { 93 CHECK(code_start != nullptr); 94 CHECK_NE(code_length, 0U); 95 uintptr_t data = reinterpret_cast<uintptr_t>(code_start); 96 uintptr_t base = RoundDown(data, kPageSize); 97 uintptr_t limit = RoundUp(data + code_length, kPageSize); 98 uintptr_t len = limit - base; 99 int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC); 100 CHECK_EQ(result, 0); 101 102 CHECK(FlushCpuCaches(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len))); 103 } 104 105 void CommonCompilerTest::SetUp() { 106 CommonRuntimeTest::SetUp(); 107 { 108 ScopedObjectAccess soa(Thread::Current()); 109 110 runtime_->SetInstructionSet(instruction_set_); 111 for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) { 112 CalleeSaveType type = CalleeSaveType(i); 113 if (!runtime_->HasCalleeSaveMethod(type)) { 114 runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(), type); 115 } 116 } 117 } 118 } 119 120 void CommonCompilerTest::ApplyInstructionSet() { 121 // Copy local instruction_set_ and instruction_set_features_ to *compiler_options_; 122 CHECK(instruction_set_features_ != nullptr); 123 if (instruction_set_ == InstructionSet::kThumb2) { 124 CHECK_EQ(InstructionSet::kArm, instruction_set_features_->GetInstructionSet()); 125 } else { 126 CHECK_EQ(instruction_set_, instruction_set_features_->GetInstructionSet()); 127 } 128 compiler_options_->instruction_set_ = instruction_set_; 129 compiler_options_->instruction_set_features_ = 130 InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap()); 131 CHECK(compiler_options_->instruction_set_features_->Equals(instruction_set_features_.get())); 132 } 133 134 void CommonCompilerTest::OverrideInstructionSetFeatures(InstructionSet instruction_set, 135 const std::string& variant) { 136 instruction_set_ = instruction_set; 137 std::string error_msg; 138 instruction_set_features_ = 139 InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg); 140 CHECK(instruction_set_features_ != nullptr) << error_msg; 141 142 if (compiler_options_ != nullptr) { 143 ApplyInstructionSet(); 144 } 145 } 146 147 void CommonCompilerTest::SetUpRuntimeOptions(RuntimeOptions* options) { 148 CommonRuntimeTest::SetUpRuntimeOptions(options); 149 150 compiler_options_.reset(new CompilerOptions); 151 verification_results_.reset(new VerificationResults(compiler_options_.get())); 152 153 ApplyInstructionSet(); 154 } 155 156 Compiler::Kind CommonCompilerTest::GetCompilerKind() const { 157 return compiler_kind_; 158 } 159 160 void CommonCompilerTest::SetCompilerKind(Compiler::Kind compiler_kind) { 161 compiler_kind_ = compiler_kind; 162 } 163 164 void CommonCompilerTest::TearDown() { 165 verification_results_.reset(); 166 compiler_options_.reset(); 167 168 CommonRuntimeTest::TearDown(); 169 } 170 171 void CommonCompilerTest::CompileMethod(ArtMethod* method) { 172 CHECK(method != nullptr); 173 TimingLogger timings("CommonCompilerTest::CompileMethod", false, false); 174 TimingLogger::ScopedTiming t(__FUNCTION__, &timings); 175 CompiledMethodStorage storage(/*swap_fd=*/ -1); 176 CompiledMethod* compiled_method = nullptr; 177 { 178 DCHECK(!Runtime::Current()->IsStarted()); 179 Thread* self = Thread::Current(); 180 StackHandleScope<2> hs(self); 181 std::unique_ptr<Compiler> compiler( 182 Compiler::Create(*compiler_options_, &storage, compiler_kind_)); 183 const DexFile& dex_file = *method->GetDexFile(); 184 Handle<mirror::DexCache> dex_cache = hs.NewHandle(class_linker_->FindDexCache(self, dex_file)); 185 Handle<mirror::ClassLoader> class_loader = hs.NewHandle(method->GetClassLoader()); 186 compiler_options_->verification_results_ = verification_results_.get(); 187 if (method->IsNative()) { 188 compiled_method = compiler->JniCompile(method->GetAccessFlags(), 189 method->GetDexMethodIndex(), 190 dex_file, 191 dex_cache); 192 } else { 193 verification_results_->AddDexFile(&dex_file); 194 verification_results_->CreateVerifiedMethodFor( 195 MethodReference(&dex_file, method->GetDexMethodIndex())); 196 compiled_method = compiler->Compile(method->GetCodeItem(), 197 method->GetAccessFlags(), 198 method->GetInvokeType(), 199 method->GetClassDefIndex(), 200 method->GetDexMethodIndex(), 201 class_loader, 202 dex_file, 203 dex_cache); 204 } 205 compiler_options_->verification_results_ = nullptr; 206 } 207 CHECK(method != nullptr); 208 { 209 TimingLogger::ScopedTiming t2("MakeExecutable", &timings); 210 MakeExecutable(method, compiled_method); 211 } 212 CompiledMethod::ReleaseSwapAllocatedCompiledMethod(&storage, compiled_method); 213 } 214 215 void CommonCompilerTest::CompileDirectMethod(Handle<mirror::ClassLoader> class_loader, 216 const char* class_name, const char* method_name, 217 const char* signature) { 218 std::string class_descriptor(DotToDescriptor(class_name)); 219 Thread* self = Thread::Current(); 220 ObjPtr<mirror::Class> klass = 221 class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); 222 CHECK(klass != nullptr) << "Class not found " << class_name; 223 auto pointer_size = class_linker_->GetImagePointerSize(); 224 ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size); 225 CHECK(method != nullptr && method->IsDirect()) << "Direct method not found: " 226 << class_name << "." << method_name << signature; 227 CompileMethod(method); 228 } 229 230 void CommonCompilerTest::CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader, 231 const char* class_name, const char* method_name, 232 const char* signature) { 233 std::string class_descriptor(DotToDescriptor(class_name)); 234 Thread* self = Thread::Current(); 235 ObjPtr<mirror::Class> klass = 236 class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); 237 CHECK(klass != nullptr) << "Class not found " << class_name; 238 auto pointer_size = class_linker_->GetImagePointerSize(); 239 ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size); 240 CHECK(method != nullptr && !method->IsDirect()) << "Virtual method not found: " 241 << class_name << "." << method_name << signature; 242 CompileMethod(method); 243 } 244 245 void CommonCompilerTest::ClearBootImageOption() { 246 compiler_options_->image_type_ = CompilerOptions::ImageType::kNone; 247 } 248 249 } // namespace art 250