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 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 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. 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