Home | History | Annotate | Download | only in linker
      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