You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
6.5 KiB
156 lines
6.5 KiB
/* |
|
* Copyright (C) 2011 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <string.h> |
|
#include <vector> |
|
|
|
#include "image_test.h" |
|
|
|
#include "image.h" |
|
#include "scoped_thread_state_change-inl.h" |
|
#include "thread.h" |
|
|
|
namespace art { |
|
|
|
TEST_F(ImageTest, TestImageLayout) { |
|
std::vector<size_t> image_sizes; |
|
std::vector<size_t> image_sizes_extra; |
|
// Compile multi-image with ImageLayoutA being the last image. |
|
{ |
|
CompilationHelper helper; |
|
Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutA", {"LMyClass;"}); |
|
image_sizes = helper.GetImageObjectSectionSizes(); |
|
} |
|
TearDown(); |
|
runtime_.reset(); |
|
SetUp(); |
|
// Compile multi-image with ImageLayoutB being the last image. |
|
{ |
|
CompilationHelper helper; |
|
Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutB", {"LMyClass;"}); |
|
image_sizes_extra = helper.GetImageObjectSectionSizes(); |
|
} |
|
// Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the |
|
// first two images. |
|
ASSERT_EQ(image_sizes.size(), image_sizes.size()); |
|
// Sizes of the images should be the same. These sizes are for the whole image unrounded. |
|
for (size_t i = 0; i < image_sizes.size() - 1; ++i) { |
|
EXPECT_EQ(image_sizes[i], image_sizes_extra[i]); |
|
} |
|
// Last image should be larger since it has a hash map and a string. |
|
EXPECT_LT(image_sizes.back(), image_sizes_extra.back()); |
|
} |
|
|
|
TEST_F(ImageTest, ImageHeaderIsValid) { |
|
uint32_t image_begin = ART_BASE_ADDRESS; |
|
uint32_t image_size_ = 16 * KB; |
|
uint32_t image_roots = ART_BASE_ADDRESS + (1 * KB); |
|
uint32_t oat_checksum = 0; |
|
uint32_t oat_file_begin = ART_BASE_ADDRESS + (4 * KB); // page aligned |
|
uint32_t oat_data_begin = ART_BASE_ADDRESS + (8 * KB); // page aligned |
|
uint32_t oat_data_end = ART_BASE_ADDRESS + (9 * KB); |
|
uint32_t oat_file_end = ART_BASE_ADDRESS + (10 * KB); |
|
ImageSection sections[ImageHeader::kSectionCount]; |
|
ImageHeader image_header(image_begin, |
|
image_size_, |
|
sections, |
|
image_roots, |
|
oat_checksum, |
|
oat_file_begin, |
|
oat_data_begin, |
|
oat_data_end, |
|
oat_file_end, |
|
/*boot_image_begin*/0U, |
|
/*boot_image_size*/0U, |
|
/*boot_oat_begin*/0U, |
|
/*boot_oat_size_*/0U, |
|
sizeof(void*), |
|
/*compile_pic*/false, |
|
/*is_pic*/false, |
|
ImageHeader::kDefaultStorageMode, |
|
/*data_size*/0u); |
|
ASSERT_TRUE(image_header.IsValid()); |
|
ASSERT_TRUE(!image_header.IsAppImage()); |
|
|
|
char* magic = const_cast<char*>(image_header.GetMagic()); |
|
strcpy(magic, ""); // bad magic |
|
ASSERT_FALSE(image_header.IsValid()); |
|
strcpy(magic, "art\n000"); // bad version |
|
ASSERT_FALSE(image_header.IsValid()); |
|
} |
|
|
|
// Test that pointer to quick code is the same in |
|
// a default method of an interface and in a copied method |
|
// of a class which implements the interface. This should be true |
|
// only if the copied method and the origin method are located in the |
|
// same oat file. |
|
TEST_F(ImageTest, TestDefaultMethods) { |
|
CompilationHelper helper; |
|
Compile(ImageHeader::kStorageModeUncompressed, |
|
helper, |
|
"DefaultMethods", |
|
{"LIface;", "LImpl;", "LIterableBase;"}); |
|
|
|
PointerSize pointer_size = class_linker_->GetImagePointerSize(); |
|
Thread* self = Thread::Current(); |
|
ScopedObjectAccess soa(self); |
|
|
|
// Test the pointer to quick code is the same in origin method |
|
// and in the copied method form the same oat file. |
|
mirror::Class* iface_klass = class_linker_->LookupClass( |
|
self, "LIface;", ObjPtr<mirror::ClassLoader>()); |
|
ASSERT_NE(nullptr, iface_klass); |
|
ArtMethod* origin = iface_klass->FindInterfaceMethod("defaultMethod", "()V", pointer_size); |
|
ASSERT_NE(nullptr, origin); |
|
ASSERT_TRUE(origin->GetDeclaringClass() == iface_klass); |
|
const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); |
|
// The origin method should have a pointer to quick code |
|
ASSERT_NE(nullptr, code); |
|
ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); |
|
mirror::Class* impl_klass = class_linker_->LookupClass( |
|
self, "LImpl;", ObjPtr<mirror::ClassLoader>()); |
|
ASSERT_NE(nullptr, impl_klass); |
|
ArtMethod* copied = FindCopiedMethod(origin, impl_klass); |
|
ASSERT_NE(nullptr, copied); |
|
// the copied method should have pointer to the same quick code as the origin method |
|
ASSERT_EQ(code, copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)); |
|
|
|
// Test the origin method has pointer to quick code |
|
// but the copied method has pointer to interpreter |
|
// because these methods are in different oat files. |
|
mirror::Class* iterable_klass = class_linker_->LookupClass( |
|
self, "Ljava/lang/Iterable;", ObjPtr<mirror::ClassLoader>()); |
|
ASSERT_NE(nullptr, iterable_klass); |
|
origin = iterable_klass->FindClassMethod( |
|
"forEach", "(Ljava/util/function/Consumer;)V", pointer_size); |
|
ASSERT_NE(nullptr, origin); |
|
ASSERT_FALSE(origin->IsDirect()); |
|
ASSERT_TRUE(origin->GetDeclaringClass() == iterable_klass); |
|
code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); |
|
// the origin method should have a pointer to quick code |
|
ASSERT_NE(nullptr, code); |
|
ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); |
|
mirror::Class* iterablebase_klass = class_linker_->LookupClass( |
|
self, "LIterableBase;", ObjPtr<mirror::ClassLoader>()); |
|
ASSERT_NE(nullptr, iterablebase_klass); |
|
copied = FindCopiedMethod(origin, iterablebase_klass); |
|
ASSERT_NE(nullptr, copied); |
|
code = copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); |
|
// the copied method should have a pointer to interpreter |
|
ASSERT_TRUE(class_linker_->IsQuickToInterpreterBridge(code)); |
|
} |
|
|
|
} // namespace art
|
|
|