Elliott Hughes | 2faa5f1 | 2012-01-30 14:42:07 -0800 | [diff] [blame] | 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 | */ |
Brian Carlstrom | db4d540 | 2011-08-09 12:18:28 -0700 | [diff] [blame] | 16 | |
Vladimir Marko | 1352f13 | 2017-04-28 15:28:29 +0100 | [diff] [blame] | 17 | #include <string.h> |
Ian Rogers | 0cfe1fb | 2011-08-26 03:29:44 -0700 | [diff] [blame] | 18 | #include <vector> |
| 19 | |
Vladimir Marko | 1352f13 | 2017-04-28 15:28:29 +0100 | [diff] [blame] | 20 | #include "image_test.h" |
Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 21 | |
Vladimir Marko | 1352f13 | 2017-04-28 15:28:29 +0100 | [diff] [blame] | 22 | #include "image.h" |
Mathieu Chartier | 0795f23 | 2016-09-27 18:43:30 -0700 | [diff] [blame] | 23 | #include "scoped_thread_state_change-inl.h" |
Vladimir Marko | 1352f13 | 2017-04-28 15:28:29 +0100 | [diff] [blame] | 24 | #include "thread.h" |
Brian Carlstrom | db4d540 | 2011-08-09 12:18:28 -0700 | [diff] [blame] | 25 | |
Brian Carlstrom | db4d540 | 2011-08-09 12:18:28 -0700 | [diff] [blame] | 26 | namespace art { |
| 27 | |
Mathieu Chartier | 496577f | 2016-09-20 15:33:31 -0700 | [diff] [blame] | 28 | TEST_F(ImageTest, TestImageLayout) { |
| 29 | std::vector<size_t> image_sizes; |
| 30 | std::vector<size_t> image_sizes_extra; |
| 31 | // Compile multi-image with ImageLayoutA being the last image. |
| 32 | { |
| 33 | CompilationHelper helper; |
Artem Udovichenko | b3f2b5c | 2017-01-31 11:49:33 +0300 | [diff] [blame] | 34 | Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutA", {"LMyClass;"}); |
Mathieu Chartier | 496577f | 2016-09-20 15:33:31 -0700 | [diff] [blame] | 35 | image_sizes = helper.GetImageObjectSectionSizes(); |
| 36 | } |
| 37 | TearDown(); |
| 38 | runtime_.reset(); |
| 39 | SetUp(); |
| 40 | // Compile multi-image with ImageLayoutB being the last image. |
| 41 | { |
| 42 | CompilationHelper helper; |
Artem Udovichenko | b3f2b5c | 2017-01-31 11:49:33 +0300 | [diff] [blame] | 43 | Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutB", {"LMyClass;"}); |
Mathieu Chartier | 496577f | 2016-09-20 15:33:31 -0700 | [diff] [blame] | 44 | image_sizes_extra = helper.GetImageObjectSectionSizes(); |
| 45 | } |
| 46 | // Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the |
| 47 | // first two images. |
| 48 | ASSERT_EQ(image_sizes.size(), image_sizes.size()); |
| 49 | // Sizes of the images should be the same. These sizes are for the whole image unrounded. |
| 50 | for (size_t i = 0; i < image_sizes.size() - 1; ++i) { |
| 51 | EXPECT_EQ(image_sizes[i], image_sizes_extra[i]); |
| 52 | } |
| 53 | // Last image should be larger since it has a hash map and a string. |
| 54 | EXPECT_LT(image_sizes.back(), image_sizes_extra.back()); |
| 55 | } |
| 56 | |
Brian Carlstrom | 179486a | 2013-09-03 11:51:42 -0700 | [diff] [blame] | 57 | TEST_F(ImageTest, ImageHeaderIsValid) { |
| 58 | uint32_t image_begin = ART_BASE_ADDRESS; |
| 59 | uint32_t image_size_ = 16 * KB; |
Brian Carlstrom | 179486a | 2013-09-03 11:51:42 -0700 | [diff] [blame] | 60 | uint32_t image_roots = ART_BASE_ADDRESS + (1 * KB); |
| 61 | uint32_t oat_checksum = 0; |
| 62 | uint32_t oat_file_begin = ART_BASE_ADDRESS + (4 * KB); // page aligned |
| 63 | uint32_t oat_data_begin = ART_BASE_ADDRESS + (8 * KB); // page aligned |
| 64 | uint32_t oat_data_end = ART_BASE_ADDRESS + (9 * KB); |
| 65 | uint32_t oat_file_end = ART_BASE_ADDRESS + (10 * KB); |
Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 66 | ImageSection sections[ImageHeader::kSectionCount]; |
Brian Carlstrom | 179486a | 2013-09-03 11:51:42 -0700 | [diff] [blame] | 67 | ImageHeader image_header(image_begin, |
| 68 | image_size_, |
Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 69 | sections, |
Brian Carlstrom | 179486a | 2013-09-03 11:51:42 -0700 | [diff] [blame] | 70 | image_roots, |
| 71 | oat_checksum, |
| 72 | oat_file_begin, |
| 73 | oat_data_begin, |
| 74 | oat_data_end, |
Igor Murashkin | 4677476 | 2014-10-22 11:37:02 -0700 | [diff] [blame] | 75 | oat_file_end, |
Mathieu Chartier | fbc3108 | 2016-01-24 11:59:56 -0800 | [diff] [blame] | 76 | /*boot_image_begin*/0U, |
| 77 | /*boot_image_size*/0U, |
| 78 | /*boot_oat_begin*/0U, |
| 79 | /*boot_oat_size_*/0U, |
Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 80 | sizeof(void*), |
Mathieu Chartier | ceb07b3 | 2015-12-10 09:33:21 -0800 | [diff] [blame] | 81 | /*compile_pic*/false, |
Mathieu Chartier | fbc3108 | 2016-01-24 11:59:56 -0800 | [diff] [blame] | 82 | /*is_pic*/false, |
Mathieu Chartier | ceb07b3 | 2015-12-10 09:33:21 -0800 | [diff] [blame] | 83 | ImageHeader::kDefaultStorageMode, |
| 84 | /*data_size*/0u); |
Brian Carlstrom | 179486a | 2013-09-03 11:51:42 -0700 | [diff] [blame] | 85 | ASSERT_TRUE(image_header.IsValid()); |
Mathieu Chartier | fbc3108 | 2016-01-24 11:59:56 -0800 | [diff] [blame] | 86 | ASSERT_TRUE(!image_header.IsAppImage()); |
Brian Carlstrom | 179486a | 2013-09-03 11:51:42 -0700 | [diff] [blame] | 87 | |
| 88 | char* magic = const_cast<char*>(image_header.GetMagic()); |
| 89 | strcpy(magic, ""); // bad magic |
| 90 | ASSERT_FALSE(image_header.IsValid()); |
| 91 | strcpy(magic, "art\n000"); // bad version |
| 92 | ASSERT_FALSE(image_header.IsValid()); |
| 93 | } |
| 94 | |
Artem Udovichenko | b3f2b5c | 2017-01-31 11:49:33 +0300 | [diff] [blame] | 95 | // Test that pointer to quick code is the same in |
| 96 | // a default method of an interface and in a copied method |
| 97 | // of a class which implements the interface. This should be true |
| 98 | // only if the copied method and the origin method are located in the |
| 99 | // same oat file. |
| 100 | TEST_F(ImageTest, TestDefaultMethods) { |
| 101 | CompilationHelper helper; |
| 102 | Compile(ImageHeader::kStorageModeUncompressed, |
| 103 | helper, |
| 104 | "DefaultMethods", |
| 105 | {"LIface;", "LImpl;", "LIterableBase;"}); |
| 106 | |
| 107 | PointerSize pointer_size = class_linker_->GetImagePointerSize(); |
| 108 | Thread* self = Thread::Current(); |
| 109 | ScopedObjectAccess soa(self); |
| 110 | |
| 111 | // Test the pointer to quick code is the same in origin method |
| 112 | // and in the copied method form the same oat file. |
| 113 | mirror::Class* iface_klass = class_linker_->LookupClass( |
| 114 | self, "LIface;", ObjPtr<mirror::ClassLoader>()); |
| 115 | ASSERT_NE(nullptr, iface_klass); |
| 116 | ArtMethod* origin = iface_klass->FindDeclaredVirtualMethod( |
| 117 | "defaultMethod", "()V", pointer_size); |
| 118 | ASSERT_NE(nullptr, origin); |
| 119 | const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); |
| 120 | // The origin method should have a pointer to quick code |
| 121 | ASSERT_NE(nullptr, code); |
| 122 | ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); |
| 123 | mirror::Class* impl_klass = class_linker_->LookupClass( |
| 124 | self, "LImpl;", ObjPtr<mirror::ClassLoader>()); |
| 125 | ASSERT_NE(nullptr, impl_klass); |
| 126 | ArtMethod* copied = FindCopiedMethod(origin, impl_klass); |
| 127 | ASSERT_NE(nullptr, copied); |
| 128 | // the copied method should have pointer to the same quick code as the origin method |
| 129 | ASSERT_EQ(code, copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)); |
| 130 | |
| 131 | // Test the origin method has pointer to quick code |
| 132 | // but the copied method has pointer to interpreter |
| 133 | // because these methods are in different oat files. |
| 134 | mirror::Class* iterable_klass = class_linker_->LookupClass( |
| 135 | self, "Ljava/lang/Iterable;", ObjPtr<mirror::ClassLoader>()); |
| 136 | ASSERT_NE(nullptr, iterable_klass); |
| 137 | origin = iterable_klass->FindDeclaredVirtualMethod( |
| 138 | "forEach", "(Ljava/util/function/Consumer;)V", pointer_size); |
| 139 | ASSERT_NE(nullptr, origin); |
| 140 | code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); |
| 141 | // the origin method should have a pointer to quick code |
| 142 | ASSERT_NE(nullptr, code); |
| 143 | ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); |
| 144 | mirror::Class* iterablebase_klass = class_linker_->LookupClass( |
| 145 | self, "LIterableBase;", ObjPtr<mirror::ClassLoader>()); |
| 146 | ASSERT_NE(nullptr, iterablebase_klass); |
| 147 | copied = FindCopiedMethod(origin, iterablebase_klass); |
| 148 | ASSERT_NE(nullptr, copied); |
| 149 | code = copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); |
| 150 | // the copied method should have a pointer to interpreter |
| 151 | ASSERT_TRUE(class_linker_->IsQuickToInterpreterBridge(code)); |
| 152 | } |
| 153 | |
Brian Carlstrom | db4d540 | 2011-08-09 12:18:28 -0700 | [diff] [blame] | 154 | } // namespace art |