• 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, helper, "ImageLayoutA", {"LMyClass;"});
36     image_sizes = helper.GetImageObjectSectionSizes();
37   }
38   TearDown();
39   runtime_.reset();
40   SetUp();
41   // Compile multi-image with ImageLayoutB being the last image.
42   {
43     CompilationHelper helper;
44     Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutB", {"LMyClass;"});
45     image_sizes_extra = helper.GetImageObjectSectionSizes();
46   }
47   // Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the
48   // first two images.
49   ASSERT_EQ(image_sizes.size(), image_sizes.size());
50   // Sizes of the object sections should be the same for all but the last image.
51   for (size_t i = 0; i < image_sizes.size() - 1; ++i) {
52     EXPECT_EQ(image_sizes[i], image_sizes_extra[i]);
53   }
54   // Last image should be larger since it has a hash map and a string.
55   EXPECT_LT(image_sizes.back(), image_sizes_extra.back());
56 }
57 
TEST_F(ImageTest,ImageHeaderIsValid)58 TEST_F(ImageTest, ImageHeaderIsValid) {
59     uint32_t image_begin = ART_BASE_ADDRESS;
60     uint32_t image_size_ = 16 * KB;
61     uint32_t image_roots = ART_BASE_ADDRESS + (1 * KB);
62     uint32_t oat_checksum = 0;
63     uint32_t oat_file_begin = ART_BASE_ADDRESS + (4 * KB);  // page aligned
64     uint32_t oat_data_begin = ART_BASE_ADDRESS + (8 * KB);  // page aligned
65     uint32_t oat_data_end = ART_BASE_ADDRESS + (9 * KB);
66     uint32_t oat_file_end = ART_BASE_ADDRESS + (10 * KB);
67     ImageSection sections[ImageHeader::kSectionCount];
68     ImageHeader image_header(image_begin,
69                              image_size_,
70                              sections,
71                              image_roots,
72                              oat_checksum,
73                              oat_file_begin,
74                              oat_data_begin,
75                              oat_data_end,
76                              oat_file_end,
77                              /*boot_image_begin*/0U,
78                              /*boot_image_size*/0U,
79                              /*boot_oat_begin*/0U,
80                              /*boot_oat_size_*/0U,
81                              sizeof(void*),
82                              /*compile_pic*/false,
83                              /*is_pic*/false,
84                              ImageHeader::kDefaultStorageMode,
85                              /*data_size*/0u);
86     ASSERT_TRUE(image_header.IsValid());
87     ASSERT_TRUE(!image_header.IsAppImage());
88 
89     char* magic = const_cast<char*>(image_header.GetMagic());
90     strcpy(magic, "");  // bad magic
91     ASSERT_FALSE(image_header.IsValid());
92     strcpy(magic, "art\n000");  // bad version
93     ASSERT_FALSE(image_header.IsValid());
94 }
95 
96 // Test that pointer to quick code is the same in
97 // a default method of an interface and in a copied method
98 // of a class which implements the interface. This should be true
99 // only if the copied method and the origin method are located in the
100 // same oat file.
TEST_F(ImageTest,TestDefaultMethods)101 TEST_F(ImageTest, TestDefaultMethods) {
102   CompilationHelper helper;
103   Compile(ImageHeader::kStorageModeUncompressed,
104       helper,
105       "DefaultMethods",
106       {"LIface;", "LImpl;", "LIterableBase;"});
107 
108   PointerSize pointer_size = class_linker_->GetImagePointerSize();
109   Thread* self = Thread::Current();
110   ScopedObjectAccess soa(self);
111 
112   // Test the pointer to quick code is the same in origin method
113   // and in the copied method form the same oat file.
114   mirror::Class* iface_klass = class_linker_->LookupClass(
115       self, "LIface;", ObjPtr<mirror::ClassLoader>());
116   ASSERT_NE(nullptr, iface_klass);
117   ArtMethod* origin = iface_klass->FindInterfaceMethod("defaultMethod", "()V", pointer_size);
118   ASSERT_NE(nullptr, origin);
119   ASSERT_TRUE(origin->GetDeclaringClass() == iface_klass);
120   const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
121   // The origin method should have a pointer to quick code
122   ASSERT_NE(nullptr, code);
123   ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code));
124   mirror::Class* impl_klass = class_linker_->LookupClass(
125       self, "LImpl;", ObjPtr<mirror::ClassLoader>());
126   ASSERT_NE(nullptr, impl_klass);
127   ArtMethod* copied = FindCopiedMethod(origin, impl_klass);
128   ASSERT_NE(nullptr, copied);
129   // the copied method should have pointer to the same quick code as the origin method
130   ASSERT_EQ(code, copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size));
131 
132   // Test the origin method has pointer to quick code
133   // but the copied method has pointer to interpreter
134   // because these methods are in different oat files.
135   mirror::Class* iterable_klass = class_linker_->LookupClass(
136       self, "Ljava/lang/Iterable;", ObjPtr<mirror::ClassLoader>());
137   ASSERT_NE(nullptr, iterable_klass);
138   origin = iterable_klass->FindClassMethod(
139       "forEach", "(Ljava/util/function/Consumer;)V", pointer_size);
140   ASSERT_NE(nullptr, origin);
141   ASSERT_FALSE(origin->IsDirect());
142   ASSERT_TRUE(origin->GetDeclaringClass() == iterable_klass);
143   code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
144   // the origin method should have a pointer to quick code
145   ASSERT_NE(nullptr, code);
146   ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code));
147   mirror::Class* iterablebase_klass = class_linker_->LookupClass(
148       self, "LIterableBase;", ObjPtr<mirror::ClassLoader>());
149   ASSERT_NE(nullptr, iterablebase_klass);
150   copied = FindCopiedMethod(origin, iterablebase_klass);
151   ASSERT_NE(nullptr, copied);
152   code = copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
153   // the copied method should have a pointer to interpreter
154   ASSERT_TRUE(class_linker_->IsQuickToInterpreterBridge(code));
155 }
156 
157 }  // namespace linker
158 }  // namespace art
159