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
179 } // namespace linker
180 } // namespace art
181