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 "driver/compiler_driver.h"
18
19 #include <limits>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <memory>
23
24 #include "art_method-inl.h"
25 #include "base/casts.h"
26 #include "class_linker-inl.h"
27 #include "common_compiler_driver_test.h"
28 #include "compiled_method-inl.h"
29 #include "compiler_callbacks.h"
30 #include "dex/dex_file.h"
31 #include "dex/dex_file_types.h"
32 #include "gc/heap.h"
33 #include "handle_scope-inl.h"
34 #include "instrumentation-inl.h"
35 #include "mirror/class-inl.h"
36 #include "mirror/class_loader.h"
37 #include "mirror/dex_cache-inl.h"
38 #include "mirror/object-inl.h"
39 #include "mirror/object_array-inl.h"
40 #include "profile/profile_compilation_info.h"
41 #include "scoped_thread_state_change-inl.h"
42
43 namespace art {
44
45 class CompilerDriverTest : public CommonCompilerDriverTest {
46 protected:
CompileAllAndMakeExecutable(jobject class_loader)47 void CompileAllAndMakeExecutable(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
48 TimingLogger timings("CompilerDriverTest::CompileAllAndMakeExecutable", false, false);
49 dex_files_ = GetDexFiles(class_loader);
50 CompileAll(class_loader, dex_files_, &timings);
51 TimingLogger::ScopedTiming t("MakeAllExecutable", &timings);
52 MakeAllExecutable(class_loader);
53 }
54
EnsureCompiled(jobject class_loader,const char * class_name,const char * method,const char * signature,bool is_virtual)55 void EnsureCompiled(jobject class_loader, const char* class_name, const char* method,
56 const char* signature, bool is_virtual)
57 REQUIRES(!Locks::mutator_lock_) {
58 CompileAllAndMakeExecutable(class_loader);
59 Thread::Current()->TransitionFromSuspendedToRunnable();
60 bool started = runtime_->Start();
61 CHECK(started);
62 env_ = Thread::Current()->GetJniEnv();
63 class_ = env_->FindClass(class_name);
64 CHECK(class_ != nullptr) << "Class not found: " << class_name;
65 if (is_virtual) {
66 mid_ = env_->GetMethodID(class_, method, signature);
67 } else {
68 mid_ = env_->GetStaticMethodID(class_, method, signature);
69 }
70 CHECK(mid_ != nullptr) << "Method not found: " << class_name << "." << method << signature;
71 }
72
MakeAllExecutable(jobject class_loader)73 void MakeAllExecutable(jobject class_loader) {
74 const std::vector<const DexFile*> class_path = GetDexFiles(class_loader);
75 for (size_t i = 0; i != class_path.size(); ++i) {
76 const DexFile* dex_file = class_path[i];
77 CHECK(dex_file != nullptr);
78 MakeDexFileExecutable(class_loader, *dex_file);
79 }
80 }
81
MakeExecutable(ArtMethod * method)82 void MakeExecutable(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
83 CHECK(method != nullptr);
84
85 const void* method_code = nullptr;
86 if (!method->IsAbstract()) {
87 MethodReference method_ref(method->GetDexFile(), method->GetDexMethodIndex());
88 const CompiledMethod* compiled_method = compiler_driver_->GetCompiledMethod(method_ref);
89 // If the code size is 0 it means the method was skipped due to profile guided compilation.
90 if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0u) {
91 method_code = CommonCompilerTest::MakeExecutable(compiled_method->GetQuickCode(),
92 compiled_method->GetVmapTable(),
93 compiled_method->GetInstructionSet());
94 LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
95 }
96 }
97 instrumentation::Instrumentation* instr = runtime_->GetInstrumentation();
98 const void* entrypoint = instr->GetInitialEntrypoint(method->GetAccessFlags(), method_code);
99 CHECK(!instr->IsForcedInterpretOnly());
100 CHECK(!instr->EntryExitStubsInstalled());
101 instr->UpdateMethodsCode(method, entrypoint);
102 }
103
MakeDexFileExecutable(jobject class_loader,const DexFile & dex_file)104 void MakeDexFileExecutable(jobject class_loader, const DexFile& dex_file) {
105 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
106 for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
107 const dex::ClassDef& class_def = dex_file.GetClassDef(i);
108 const char* descriptor = dex_file.GetClassDescriptor(class_def);
109 ScopedObjectAccess soa(Thread::Current());
110 StackHandleScope<1> hs(soa.Self());
111 Handle<mirror::ClassLoader> loader(
112 hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
113 ObjPtr<mirror::Class> c = FindClass(descriptor, loader);
114 CHECK(c != nullptr);
115 const auto pointer_size = class_linker->GetImagePointerSize();
116 for (auto& m : c->GetMethods(pointer_size)) {
117 MakeExecutable(&m);
118 }
119 }
120 }
121
122 JNIEnv* env_;
123 jclass class_;
124 jmethodID mid_;
125 std::vector<const DexFile*> dex_files_;
126 };
127
128 // Disabled due to 10 second runtime on host
129 // TODO: Update the test for hash-based dex cache arrays. Bug: 30627598
TEST_F(CompilerDriverTest,DISABLED_LARGE_CompileDexLibCore)130 TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) {
131 CompileAllAndMakeExecutable(nullptr);
132
133 // All libcore references should resolve
134 ScopedObjectAccess soa(Thread::Current());
135 ASSERT_TRUE(java_lang_dex_file_ != nullptr);
136 const DexFile& dex = *java_lang_dex_file_;
137 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(soa.Self(), dex);
138 for (size_t i = 0; i < dex_cache->NumStrings(); i++) {
139 const ObjPtr<mirror::String> string = dex_cache->GetResolvedString(dex::StringIndex(i));
140 EXPECT_TRUE(string != nullptr) << "string_idx=" << i;
141 }
142 for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
143 const ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(dex::TypeIndex(i));
144 EXPECT_TRUE(type != nullptr)
145 << "type_idx=" << i << " " << dex.GetTypeDescriptor(dex.GetTypeId(dex::TypeIndex(i)));
146 }
147 for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
148 // FIXME: This is outdated for hash-based method array.
149 ArtMethod* method = dex_cache->GetResolvedMethod(i);
150 EXPECT_TRUE(method != nullptr) << "method_idx=" << i
151 << " " << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i))
152 << " " << dex.GetMethodName(dex.GetMethodId(i));
153 EXPECT_TRUE(method->GetEntryPointFromQuickCompiledCode() != nullptr) << "method_idx=" << i
154 << " " << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i)) << " "
155 << dex.GetMethodName(dex.GetMethodId(i));
156 }
157 for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
158 // FIXME: This is outdated for hash-based field array.
159 ArtField* field = dex_cache->GetResolvedField(i);
160 EXPECT_TRUE(field != nullptr) << "field_idx=" << i
161 << " " << dex.GetFieldDeclaringClassDescriptor(dex.GetFieldId(i))
162 << " " << dex.GetFieldName(dex.GetFieldId(i));
163 }
164
165 // TODO check Class::IsVerified for all classes
166
167 // TODO: check that all Method::GetCode() values are non-null
168 }
169
TEST_F(CompilerDriverTest,AbstractMethodErrorStub)170 TEST_F(CompilerDriverTest, AbstractMethodErrorStub) {
171 jobject class_loader;
172 {
173 ScopedObjectAccess soa(Thread::Current());
174 class_loader = LoadDex("AbstractMethod");
175 }
176 ASSERT_TRUE(class_loader != nullptr);
177 EnsureCompiled(class_loader, "AbstractClass", "foo", "()V", true);
178
179 // Create a jobj_ of ConcreteClass, NOT AbstractClass.
180 jclass c_class = env_->FindClass("ConcreteClass");
181
182 jmethodID constructor = env_->GetMethodID(c_class, "<init>", "()V");
183
184 jobject jobj_ = env_->NewObject(c_class, constructor);
185 ASSERT_TRUE(jobj_ != nullptr);
186
187 // Force non-virtual call to AbstractClass foo, will throw AbstractMethodError exception.
188 env_->CallNonvirtualVoidMethod(jobj_, class_, mid_);
189
190 EXPECT_EQ(env_->ExceptionCheck(), JNI_TRUE);
191 jthrowable exception = env_->ExceptionOccurred();
192 env_->ExceptionClear();
193 jclass jlame = env_->FindClass("java/lang/AbstractMethodError");
194 EXPECT_TRUE(env_->IsInstanceOf(exception, jlame));
195 {
196 ScopedObjectAccess soa(Thread::Current());
197 Thread::Current()->ClearException();
198 }
199 }
200
201 class CompilerDriverProfileTest : public CompilerDriverTest {
202 protected:
GetProfileCompilationInfo()203 ProfileCompilationInfo* GetProfileCompilationInfo() override {
204 ScopedObjectAccess soa(Thread::Current());
205 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
206
207 ProfileCompilationInfo info;
208 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
209 profile_info_.AddMethod(ProfileMethodInfo(MethodReference(dex_file.get(), 1)),
210 ProfileCompilationInfo::MethodHotness::kFlagHot);
211 profile_info_.AddMethod(ProfileMethodInfo(MethodReference(dex_file.get(), 2)),
212 ProfileCompilationInfo::MethodHotness::kFlagHot);
213 }
214 return &profile_info_;
215 }
216
GetCompilerFilter() const217 CompilerFilter::Filter GetCompilerFilter() const override {
218 // Use a profile based filter.
219 return CompilerFilter::kSpeedProfile;
220 }
221
GetExpectedMethodsForClass(const std::string & clazz)222 std::unordered_set<std::string> GetExpectedMethodsForClass(const std::string& clazz) {
223 if (clazz == "Main") {
224 return std::unordered_set<std::string>({
225 "java.lang.String Main.getA()",
226 "java.lang.String Main.getB()"});
227 } else if (clazz == "Second") {
228 return std::unordered_set<std::string>({
229 "java.lang.String Second.getX()",
230 "java.lang.String Second.getY()"});
231 } else {
232 return std::unordered_set<std::string>();
233 }
234 }
235
CheckCompiledMethods(jobject class_loader,const std::string & clazz,const std::unordered_set<std::string> & expected_methods)236 void CheckCompiledMethods(jobject class_loader,
237 const std::string& clazz,
238 const std::unordered_set<std::string>& expected_methods) {
239 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
240 Thread* self = Thread::Current();
241 ScopedObjectAccess soa(self);
242 StackHandleScope<1> hs(self);
243 Handle<mirror::ClassLoader> h_loader(
244 hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
245 ObjPtr<mirror::Class> klass = FindClass(clazz.c_str(), h_loader);
246 ASSERT_NE(klass, nullptr);
247
248 const auto pointer_size = class_linker->GetImagePointerSize();
249 size_t number_of_compiled_methods = 0;
250 for (auto& m : klass->GetVirtualMethods(pointer_size)) {
251 std::string name = m.PrettyMethod(true);
252 const void* code = m.GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
253 ASSERT_NE(code, nullptr);
254 if (expected_methods.find(name) != expected_methods.end()) {
255 number_of_compiled_methods++;
256 EXPECT_FALSE(class_linker->IsQuickToInterpreterBridge(code));
257 } else {
258 EXPECT_TRUE(class_linker->IsQuickToInterpreterBridge(code));
259 }
260 }
261 EXPECT_EQ(expected_methods.size(), number_of_compiled_methods);
262 }
263
264 private:
265 ProfileCompilationInfo profile_info_;
266 };
267
TEST_F(CompilerDriverProfileTest,ProfileGuidedCompilation)268 TEST_F(CompilerDriverProfileTest, ProfileGuidedCompilation) {
269 Thread* self = Thread::Current();
270 jobject class_loader;
271 {
272 ScopedObjectAccess soa(self);
273 class_loader = LoadDex("ProfileTestMultiDex");
274 }
275 ASSERT_NE(class_loader, nullptr);
276
277 // Need to enable dex-file writability. Methods rejected to be compiled will run through the
278 // dex-to-dex compiler.
279 for (const DexFile* dex_file : GetDexFiles(class_loader)) {
280 ASSERT_TRUE(dex_file->EnableWrite());
281 }
282
283 CompileAllAndMakeExecutable(class_loader);
284
285 std::unordered_set<std::string> m = GetExpectedMethodsForClass("Main");
286 std::unordered_set<std::string> s = GetExpectedMethodsForClass("Second");
287 CheckCompiledMethods(class_loader, "LMain;", m);
288 CheckCompiledMethods(class_loader, "LSecond;", s);
289 }
290
291 // Test that a verify only compiler filter updates the CompiledClass map,
292 // which will be used for OatClass.
293 class CompilerDriverVerifyTest : public CompilerDriverTest {
294 protected:
GetCompilerFilter() const295 CompilerFilter::Filter GetCompilerFilter() const override {
296 return CompilerFilter::kVerify;
297 }
298
CheckVerifiedClass(jobject class_loader,const std::string & clazz) const299 void CheckVerifiedClass(jobject class_loader, const std::string& clazz) const {
300 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
301 Thread* self = Thread::Current();
302 ScopedObjectAccess soa(self);
303 StackHandleScope<1> hs(self);
304 Handle<mirror::ClassLoader> h_loader(
305 hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
306 ObjPtr<mirror::Class> klass = FindClass(clazz.c_str(), h_loader);
307 ASSERT_NE(klass, nullptr);
308 EXPECT_TRUE(klass->IsVerified());
309
310 ClassStatus status;
311 bool found = compiler_driver_->GetCompiledClass(
312 ClassReference(&klass->GetDexFile(), klass->GetDexTypeIndex().index_), &status);
313 ASSERT_TRUE(found);
314 EXPECT_GE(status, ClassStatus::kVerified);
315 }
316 };
317
TEST_F(CompilerDriverVerifyTest,VerifyCompilation)318 TEST_F(CompilerDriverVerifyTest, VerifyCompilation) {
319 Thread* self = Thread::Current();
320 jobject class_loader;
321 {
322 ScopedObjectAccess soa(self);
323 class_loader = LoadDex("ProfileTestMultiDex");
324 }
325 ASSERT_NE(class_loader, nullptr);
326
327 CompileAllAndMakeExecutable(class_loader);
328
329 CheckVerifiedClass(class_loader, "LMain;");
330 CheckVerifiedClass(class_loader, "LSecond;");
331 }
332
333 // Test that a class of status ClassStatus::kRetryVerificationAtRuntime is indeed
334 // recorded that way in the driver.
TEST_F(CompilerDriverVerifyTest,RetryVerifcationStatusCheckVerified)335 TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) {
336 Thread* const self = Thread::Current();
337 jobject class_loader;
338 std::vector<const DexFile*> dex_files;
339 const DexFile* dex_file = nullptr;
340 {
341 ScopedObjectAccess soa(self);
342 class_loader = LoadDex("ProfileTestMultiDex");
343 ASSERT_NE(class_loader, nullptr);
344 dex_files = GetDexFiles(class_loader);
345 ASSERT_GT(dex_files.size(), 0u);
346 dex_file = dex_files.front();
347 }
348 SetDexFilesForOatFile(dex_files);
349 callbacks_->SetDoesClassUnloading(true, compiler_driver_.get());
350 ClassReference ref(dex_file, 0u);
351 // Test that the status is read from the compiler driver as expected.
352 static_assert(enum_cast<size_t>(ClassStatus::kLast) < std::numeric_limits<size_t>::max(),
353 "Make sure incrementing the class status does not overflow.");
354 for (size_t i = enum_cast<size_t>(ClassStatus::kRetryVerificationAtRuntime);
355 i <= enum_cast<size_t>(ClassStatus::kLast);
356 ++i) {
357 const ClassStatus expected_status = enum_cast<ClassStatus>(i);
358 // Skip unsupported status that are not supposed to be ever recorded.
359 if (expected_status == ClassStatus::kInitializing ||
360 expected_status == ClassStatus::kInitialized) {
361 continue;
362 }
363 compiler_driver_->RecordClassStatus(ref, expected_status);
364 ClassStatus status = {};
365 ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status));
366 EXPECT_EQ(status, expected_status);
367 }
368 }
369
370 // TODO: need check-cast test (when stub complete & we can throw/catch
371
372 } // namespace art
373