• 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 "driver/compiler_driver.h"
18 
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <memory>
22 
23 #include "art_method-inl.h"
24 #include "class_linker-inl.h"
25 #include "common_compiler_test.h"
26 #include "dex_file.h"
27 #include "gc/heap.h"
28 #include "mirror/class-inl.h"
29 #include "mirror/class_loader.h"
30 #include "mirror/dex_cache-inl.h"
31 #include "mirror/object_array-inl.h"
32 #include "mirror/object-inl.h"
33 #include "handle_scope-inl.h"
34 #include "jit/offline_profiling_info.h"
35 #include "scoped_thread_state_change.h"
36 
37 namespace art {
38 
39 class CompilerDriverTest : public CommonCompilerTest {
40  protected:
CompileAll(jobject class_loader)41   void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
42     TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
43     TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
44     compiler_driver_->CompileAll(class_loader,
45                                  GetDexFiles(class_loader),
46                                  &timings);
47     t.NewTiming("MakeAllExecutable");
48     MakeAllExecutable(class_loader);
49   }
50 
EnsureCompiled(jobject class_loader,const char * class_name,const char * method,const char * signature,bool is_virtual)51   void EnsureCompiled(jobject class_loader, const char* class_name, const char* method,
52                       const char* signature, bool is_virtual)
53       REQUIRES(!Locks::mutator_lock_) {
54     CompileAll(class_loader);
55     Thread::Current()->TransitionFromSuspendedToRunnable();
56     bool started = runtime_->Start();
57     CHECK(started);
58     env_ = Thread::Current()->GetJniEnv();
59     class_ = env_->FindClass(class_name);
60     CHECK(class_ != nullptr) << "Class not found: " << class_name;
61     if (is_virtual) {
62       mid_ = env_->GetMethodID(class_, method, signature);
63     } else {
64       mid_ = env_->GetStaticMethodID(class_, method, signature);
65     }
66     CHECK(mid_ != nullptr) << "Method not found: " << class_name << "." << method << signature;
67   }
68 
MakeAllExecutable(jobject class_loader)69   void MakeAllExecutable(jobject class_loader) {
70     const std::vector<const DexFile*> class_path = GetDexFiles(class_loader);
71     for (size_t i = 0; i != class_path.size(); ++i) {
72       const DexFile* dex_file = class_path[i];
73       CHECK(dex_file != nullptr);
74       MakeDexFileExecutable(class_loader, *dex_file);
75     }
76   }
77 
MakeDexFileExecutable(jobject class_loader,const DexFile & dex_file)78   void MakeDexFileExecutable(jobject class_loader, const DexFile& dex_file) {
79     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
80     for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
81       const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
82       const char* descriptor = dex_file.GetClassDescriptor(class_def);
83       ScopedObjectAccess soa(Thread::Current());
84       StackHandleScope<1> hs(soa.Self());
85       Handle<mirror::ClassLoader> loader(
86           hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
87       mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader);
88       CHECK(c != nullptr);
89       const auto pointer_size = class_linker->GetImagePointerSize();
90       for (auto& m : c->GetMethods(pointer_size)) {
91         MakeExecutable(&m);
92       }
93     }
94   }
95 
96   JNIEnv* env_;
97   jclass class_;
98   jmethodID mid_;
99 };
100 
101 // Disabled due to 10 second runtime on host
TEST_F(CompilerDriverTest,DISABLED_LARGE_CompileDexLibCore)102 TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) {
103   CompileAll(nullptr);
104 
105   // All libcore references should resolve
106   ScopedObjectAccess soa(Thread::Current());
107   ASSERT_TRUE(java_lang_dex_file_ != nullptr);
108   const DexFile& dex = *java_lang_dex_file_;
109   mirror::DexCache* dex_cache = class_linker_->FindDexCache(soa.Self(), dex);
110   EXPECT_EQ(dex.NumStringIds(), dex_cache->NumStrings());
111   for (size_t i = 0; i < dex_cache->NumStrings(); i++) {
112     const mirror::String* string = dex_cache->GetResolvedString(i);
113     EXPECT_TRUE(string != nullptr) << "string_idx=" << i;
114   }
115   EXPECT_EQ(dex.NumTypeIds(), dex_cache->NumResolvedTypes());
116   for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
117     mirror::Class* type = dex_cache->GetResolvedType(i);
118     EXPECT_TRUE(type != nullptr) << "type_idx=" << i
119                               << " " << dex.GetTypeDescriptor(dex.GetTypeId(i));
120   }
121   EXPECT_EQ(dex.NumMethodIds(), dex_cache->NumResolvedMethods());
122   auto* cl = Runtime::Current()->GetClassLinker();
123   auto pointer_size = cl->GetImagePointerSize();
124   for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
125     ArtMethod* method = dex_cache->GetResolvedMethod(i, pointer_size);
126     EXPECT_TRUE(method != nullptr) << "method_idx=" << i
127                                 << " " << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i))
128                                 << " " << dex.GetMethodName(dex.GetMethodId(i));
129     EXPECT_TRUE(method->GetEntryPointFromQuickCompiledCode() != nullptr) << "method_idx=" << i
130         << " " << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i)) << " "
131         << dex.GetMethodName(dex.GetMethodId(i));
132   }
133   EXPECT_EQ(dex.NumFieldIds(), dex_cache->NumResolvedFields());
134   for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
135     ArtField* field = cl->GetResolvedField(i, dex_cache);
136     EXPECT_TRUE(field != nullptr) << "field_idx=" << i
137                                << " " << dex.GetFieldDeclaringClassDescriptor(dex.GetFieldId(i))
138                                << " " << dex.GetFieldName(dex.GetFieldId(i));
139   }
140 
141   // TODO check Class::IsVerified for all classes
142 
143   // TODO: check that all Method::GetCode() values are non-null
144 }
145 
TEST_F(CompilerDriverTest,AbstractMethodErrorStub)146 TEST_F(CompilerDriverTest, AbstractMethodErrorStub) {
147   TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS();
148   jobject class_loader;
149   {
150     ScopedObjectAccess soa(Thread::Current());
151     class_loader = LoadDex("AbstractMethod");
152   }
153   ASSERT_TRUE(class_loader != nullptr);
154   EnsureCompiled(class_loader, "AbstractClass", "foo", "()V", true);
155 
156   // Create a jobj_ of ConcreteClass, NOT AbstractClass.
157   jclass c_class = env_->FindClass("ConcreteClass");
158 
159   jmethodID constructor = env_->GetMethodID(c_class, "<init>", "()V");
160 
161   jobject jobj_ = env_->NewObject(c_class, constructor);
162   ASSERT_TRUE(jobj_ != nullptr);
163 
164   // Force non-virtual call to AbstractClass foo, will throw AbstractMethodError exception.
165   env_->CallNonvirtualVoidMethod(jobj_, class_, mid_);
166 
167   EXPECT_EQ(env_->ExceptionCheck(), JNI_TRUE);
168   jthrowable exception = env_->ExceptionOccurred();
169   env_->ExceptionClear();
170   jclass jlame = env_->FindClass("java/lang/AbstractMethodError");
171   EXPECT_TRUE(env_->IsInstanceOf(exception, jlame));
172   {
173     ScopedObjectAccess soa(Thread::Current());
174     Thread::Current()->ClearException();
175   }
176 }
177 
178 class CompilerDriverMethodsTest : public CompilerDriverTest {
179  protected:
GetCompiledMethods()180   std::unordered_set<std::string>* GetCompiledMethods() OVERRIDE {
181     return new std::unordered_set<std::string>({
182       "byte StaticLeafMethods.identity(byte)",
183       "int StaticLeafMethods.sum(int, int, int)",
184       "double StaticLeafMethods.sum(double, double, double, double)"
185     });
186   }
187 };
188 
TEST_F(CompilerDriverMethodsTest,Selection)189 TEST_F(CompilerDriverMethodsTest, Selection) {
190   TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS();
191   Thread* self = Thread::Current();
192   jobject class_loader;
193   {
194     ScopedObjectAccess soa(self);
195     class_loader = LoadDex("StaticLeafMethods");
196   }
197   ASSERT_NE(class_loader, nullptr);
198 
199   // Need to enable dex-file writability. Methods rejected to be compiled will run through the
200   // dex-to-dex compiler.
201   for (const DexFile* dex_file : GetDexFiles(class_loader)) {
202     ASSERT_TRUE(dex_file->EnableWrite());
203   }
204 
205   CompileAll(class_loader);
206 
207   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
208   ScopedObjectAccess soa(self);
209   StackHandleScope<1> hs(self);
210   Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
211       reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader))));
212   mirror::Class* klass = class_linker->FindClass(self, "LStaticLeafMethods;", h_loader);
213   ASSERT_NE(klass, nullptr);
214 
215   std::unique_ptr<std::unordered_set<std::string>> expected(GetCompiledMethods());
216 
217   const auto pointer_size = class_linker->GetImagePointerSize();
218   for (auto& m : klass->GetDirectMethods(pointer_size)) {
219     std::string name = PrettyMethod(&m, true);
220     const void* code = m.GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
221     ASSERT_NE(code, nullptr);
222     if (expected->find(name) != expected->end()) {
223       expected->erase(name);
224       EXPECT_FALSE(class_linker->IsQuickToInterpreterBridge(code));
225     } else {
226       EXPECT_TRUE(class_linker->IsQuickToInterpreterBridge(code));
227     }
228   }
229   EXPECT_TRUE(expected->empty());
230 }
231 
232 class CompilerDriverProfileTest : public CompilerDriverTest {
233  protected:
GetProfileCompilationInfo()234   ProfileCompilationInfo* GetProfileCompilationInfo() OVERRIDE {
235     ScopedObjectAccess soa(Thread::Current());
236     std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ProfileTestMultiDex");
237 
238     ProfileCompilationInfo info;
239     for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
240       std::string key = ProfileCompilationInfo::GetProfileDexFileKey(dex_file->GetLocation());
241       profile_info_.AddMethodIndex(key, dex_file->GetLocationChecksum(), 1);
242       profile_info_.AddMethodIndex(key, dex_file->GetLocationChecksum(), 2);
243     }
244     return &profile_info_;
245   }
246 
GetExpectedMethodsForClass(const std::string & clazz)247   std::unordered_set<std::string> GetExpectedMethodsForClass(const std::string& clazz) {
248     if (clazz == "Main") {
249       return std::unordered_set<std::string>({
250           "java.lang.String Main.getA()",
251           "java.lang.String Main.getB()"});
252     } else if (clazz == "Second") {
253       return std::unordered_set<std::string>({
254           "java.lang.String Second.getX()",
255           "java.lang.String Second.getY()"});
256     } else {
257       return std::unordered_set<std::string>();
258     }
259   }
260 
CheckCompiledMethods(jobject class_loader,const std::string & clazz,const std::unordered_set<std::string> & expected_methods)261   void CheckCompiledMethods(jobject class_loader,
262                             const std::string& clazz,
263                             const std::unordered_set<std::string>& expected_methods) {
264     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
265     Thread* self = Thread::Current();
266     ScopedObjectAccess soa(self);
267     StackHandleScope<1> hs(self);
268     Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
269         reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader))));
270     mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
271     ASSERT_NE(klass, nullptr);
272 
273     const auto pointer_size = class_linker->GetImagePointerSize();
274     size_t number_of_compiled_methods = 0;
275     for (auto& m : klass->GetVirtualMethods(pointer_size)) {
276       std::string name = PrettyMethod(&m, true);
277       const void* code = m.GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
278       ASSERT_NE(code, nullptr);
279       if (expected_methods.find(name) != expected_methods.end()) {
280         number_of_compiled_methods++;
281         EXPECT_FALSE(class_linker->IsQuickToInterpreterBridge(code));
282       } else {
283         EXPECT_TRUE(class_linker->IsQuickToInterpreterBridge(code));
284       }
285     }
286     EXPECT_EQ(expected_methods.size(), number_of_compiled_methods);
287   }
288 
289  private:
290   ProfileCompilationInfo profile_info_;
291 };
292 
TEST_F(CompilerDriverProfileTest,ProfileGuidedCompilation)293 TEST_F(CompilerDriverProfileTest, ProfileGuidedCompilation) {
294   TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS();
295   Thread* self = Thread::Current();
296   jobject class_loader;
297   {
298     ScopedObjectAccess soa(self);
299     class_loader = LoadDex("ProfileTestMultiDex");
300   }
301   ASSERT_NE(class_loader, nullptr);
302 
303   // Need to enable dex-file writability. Methods rejected to be compiled will run through the
304   // dex-to-dex compiler.
305   ProfileCompilationInfo info;
306   for (const DexFile* dex_file : GetDexFiles(class_loader)) {
307     ASSERT_TRUE(dex_file->EnableWrite());
308   }
309 
310   CompileAll(class_loader);
311 
312   std::unordered_set<std::string> m = GetExpectedMethodsForClass("Main");
313   std::unordered_set<std::string> s = GetExpectedMethodsForClass("Second");
314   CheckCompiledMethods(class_loader, "LMain;", m);
315   CheckCompiledMethods(class_loader, "LSecond;", s);
316 }
317 
318 // TODO: need check-cast test (when stub complete & we can throw/catch
319 
320 }  // namespace art
321