• 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 <string.h>
18 #include <vector>
19 
20 #include "image_test.h"
21 
22 #include "image.h"
23 #include "scoped_thread_state_change-inl.h"
24 #include "thread.h"
25 
26 namespace art {
27 namespace linker {
28 
TEST_F(ImageTest,TestImageLayout)29 TEST_F(ImageTest, TestImageLayout) {
30   std::vector<size_t> image_sizes;
31   std::vector<size_t> image_sizes_extra;
32   // Compile multi-image with ImageLayoutA being the last image.
33   {
34     CompilationHelper helper;
35     Compile(ImageHeader::kStorageModeUncompressed,
36             /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
37             helper,
38             "ImageLayoutA",
39             {"LMyClass;"});
40     image_sizes = helper.GetImageObjectSectionSizes();
41   }
42   TearDown();
43   runtime_.reset();
44   SetUp();
45   // Compile multi-image with ImageLayoutB being the last image.
46   {
47     CompilationHelper helper;
48     Compile(ImageHeader::kStorageModeUncompressed,
49             /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
50             helper,
51             "ImageLayoutB",
52             {"LMyClass;"});
53     image_sizes_extra = helper.GetImageObjectSectionSizes();
54   }
55   // Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the
56   // first two images.
57   ASSERT_EQ(image_sizes.size(), image_sizes.size());
58   // Sizes of the object sections should be the same for all but the last image.
59   for (size_t i = 0; i < image_sizes.size() - 1; ++i) {
60     EXPECT_EQ(image_sizes[i], image_sizes_extra[i]);
61   }
62   // Last image should be larger since it has a hash map and a string.
63   EXPECT_LT(image_sizes.back(), image_sizes_extra.back());
64 }
65 
TEST_F(ImageTest,ImageHeaderIsValid)66 TEST_F(ImageTest, ImageHeaderIsValid) {
67     uint32_t image_begin = ART_BASE_ADDRESS;
68     uint32_t image_size_ = 16 * KB;
69     uint32_t image_roots = ART_BASE_ADDRESS + (1 * KB);
70     uint32_t oat_checksum = 0;
71     uint32_t oat_file_begin = ART_BASE_ADDRESS + (4 * KB);  // page aligned
72     uint32_t oat_data_begin = ART_BASE_ADDRESS + (8 * KB);  // page aligned
73     uint32_t oat_data_end = ART_BASE_ADDRESS + (9 * KB);
74     uint32_t oat_file_end = ART_BASE_ADDRESS + (10 * KB);
75     ImageSection sections[ImageHeader::kSectionCount];
76     uint32_t image_reservation_size = RoundUp(oat_file_end - image_begin, kPageSize);
77     ImageHeader image_header(image_reservation_size,
78                              /*component_count=*/ 1u,
79                              image_begin,
80                              image_size_,
81                              sections,
82                              image_roots,
83                              oat_checksum,
84                              oat_file_begin,
85                              oat_data_begin,
86                              oat_data_end,
87                              oat_file_end,
88                              /*boot_image_begin=*/ 0u,
89                              /*boot_image_size=*/ 0u,
90                              /*boot_image_component_count=*/ 0u,
91                              /*boot_image_checksum=*/ 0u,
92                              sizeof(void*));
93 
94     ASSERT_TRUE(image_header.IsValid());
95     ASSERT_TRUE(!image_header.IsAppImage());
96 
97     char* magic = const_cast<char*>(image_header.GetMagic());
98     strcpy(magic, "");  // bad magic
99     ASSERT_FALSE(image_header.IsValid());
100     strcpy(magic, "art\n000");  // bad version
101     ASSERT_FALSE(image_header.IsValid());
102 }
103 
104 // Test that pointer to quick code is the same in
105 // a default method of an interface and in a copied method
106 // of a class which implements the interface. This should be true
107 // only if the copied method and the origin method are located in the
108 // same oat file.
TEST_F(ImageTest,TestDefaultMethods)109 TEST_F(ImageTest, TestDefaultMethods) {
110   CompilationHelper helper;
111   Compile(ImageHeader::kStorageModeUncompressed,
112           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
113           helper,
114           "DefaultMethods",
115           {"LIface;", "LImpl;", "LIterableBase;"});
116 
117   PointerSize pointer_size = class_linker_->GetImagePointerSize();
118   Thread* self = Thread::Current();
119   ScopedObjectAccess soa(self);
120 
121   // Test the pointer to quick code is the same in origin method
122   // and in the copied method form the same oat file.
123   ObjPtr<mirror::Class> iface_klass =
124       class_linker_->LookupClass(self, "LIface;", /*class_loader=*/ nullptr);
125   ASSERT_NE(nullptr, iface_klass);
126   ArtMethod* origin = iface_klass->FindInterfaceMethod("defaultMethod", "()V", pointer_size);
127   ASSERT_NE(nullptr, origin);
128   ASSERT_OBJ_PTR_EQ(origin->GetDeclaringClass(), iface_klass);
129   const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
130   // The origin method should have a pointer to quick code
131   ASSERT_NE(nullptr, code);
132   ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code));
133   ObjPtr<mirror::Class> impl_klass =
134       class_linker_->LookupClass(self, "LImpl;", /*class_loader=*/ nullptr);
135   ASSERT_NE(nullptr, impl_klass);
136   ArtMethod* copied = FindCopiedMethod(origin, impl_klass);
137   ASSERT_NE(nullptr, copied);
138   // the copied method should have pointer to the same quick code as the origin method
139   ASSERT_EQ(code, copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size));
140 
141   // Test the origin method has pointer to quick code
142   // but the copied method has pointer to interpreter
143   // because these methods are in different oat files.
144   ObjPtr<mirror::Class> iterable_klass =
145       class_linker_->LookupClass(self, "Ljava/lang/Iterable;", /*class_loader=*/ nullptr);
146   ASSERT_NE(nullptr, iterable_klass);
147   origin = iterable_klass->FindClassMethod(
148       "forEach", "(Ljava/util/function/Consumer;)V", pointer_size);
149   ASSERT_NE(nullptr, origin);
150   ASSERT_FALSE(origin->IsDirect());
151   ASSERT_OBJ_PTR_EQ(origin->GetDeclaringClass(), iterable_klass);
152   code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
153   // the origin method should have a pointer to quick code
154   ASSERT_NE(nullptr, code);
155   ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code));
156   ObjPtr<mirror::Class> iterablebase_klass =
157       class_linker_->LookupClass(self, "LIterableBase;", /*class_loader=*/ nullptr);
158   ASSERT_NE(nullptr, iterablebase_klass);
159   copied = FindCopiedMethod(origin, iterablebase_klass);
160   ASSERT_NE(nullptr, copied);
161   code = copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
162   // the copied method should have a pointer to interpreter
163   ASSERT_TRUE(class_linker_->IsQuickToInterpreterBridge(code));
164 }
165 
166 // Regression test for dex2oat crash for soft verification failure during
167 // class initialization check from the transactional interpreter while
168 // running the class initializer for another class.
TEST_F(ImageTest,TestSoftVerificationFailureDuringClassInitialization)169 TEST_F(ImageTest, TestSoftVerificationFailureDuringClassInitialization) {
170   CompilationHelper helper;
171   Compile(ImageHeader::kStorageModeUncompressed,
172           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
173           helper,
174           "VerifySoftFailDuringClinit",
175           /*image_classes=*/ {"LClassToInitialize;"},
176           /*image_classes_failing_aot_clinit=*/ {"LClassToInitialize;"});
177 }
178 
TEST_F(ImageTest,TestImageClassWithArrayClassWithUnresolvedComponent)179 TEST_F(ImageTest, TestImageClassWithArrayClassWithUnresolvedComponent) {
180   CompilationHelper helper;
181   Compile(ImageHeader::kStorageModeUncompressed,
182           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
183           helper,
184           "ArrayClassWithUnresolvedComponent",
185           /*image_classes=*/ {"LClassWithStatic;",
186                               "LClassWithStaticConst;",
187                               "[LClassWithMissingInterface;",
188                               "[[LClassWithMissingInterface;",
189                               "[LClassWithMissingSuper",
190                               "[[LClassWithMissingSuper"},
191           /*image_classes_failing_aot_clinit=*/ {
192                               "LClassWithStatic;",
193                               "LClassWithStaticConst;"},
194           /*image_classes_failing_resolution=*/ {
195                               "[LClassWithMissingInterface;",
196                               "[[LClassWithMissingInterface;",
197                               "[LClassWithMissingSuper",
198                               "[[LClassWithMissingSuper"});
199 }
200 
TEST_F(ImageTest,TestSuperWithAccessChecks)201 TEST_F(ImageTest, TestSuperWithAccessChecks) {
202   CompilationHelper helper;
203   Compile(ImageHeader::kStorageModeUncompressed,
204           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
205           helper,
206           "SuperWithAccessChecks",
207           /*image_classes=*/ {"LSubClass;", "LImplementsClass;"},
208           /*image_classes_failing_aot_clinit=*/ {"LSubClass;", "LImplementsClass;"});
209 }
210 
211 }  // namespace linker
212 }  // namespace art
213