oat_test.cc revision ea3fa0b4ba13d7bd7f7c1cd85202ccbe141a35ae
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 "compiler/oat_writer.h"
18#include "mirror/art_method-inl.h"
19#include "mirror/class-inl.h"
20#include "mirror/object_array-inl.h"
21#include "mirror/object-inl.h"
22#include "oat_file.h"
23#include "vector_output_stream.h"
24
25#include "common_test.h"
26
27namespace art {
28
29class OatTest : public CommonTest {
30 protected:
31  static const bool kCompile = false;  // DISABLED_ due to the time to compile libcore
32
33  void CheckMethod(mirror::ArtMethod* method,
34                   const OatFile::OatMethod& oat_method,
35                   const DexFile* dex_file)
36      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
37    const CompiledMethod* compiled_method =
38        compiler_driver_->GetCompiledMethod(MethodReference(dex_file,
39                                                            method->GetDexMethodIndex()));
40
41    if (compiled_method == NULL) {
42      EXPECT_TRUE(oat_method.GetQuickCode() == NULL) << PrettyMethod(method) << " "
43                                                     << oat_method.GetQuickCode();
44      EXPECT_TRUE(oat_method.GetPortableCode() == NULL) << PrettyMethod(method) << " "
45                                                        << oat_method.GetPortableCode();
46      EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U);
47      EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
48      EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
49    } else {
50      const void* quick_oat_code = oat_method.GetQuickCode();
51      if (quick_oat_code != nullptr) {
52        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
53        EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
54        EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
55        uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(quick_oat_code), 2);
56        quick_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
57        const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
58        EXPECT_TRUE(quick_code != nullptr);
59        size_t code_size = quick_code->size() * sizeof(quick_code[0]);
60        EXPECT_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size))
61            << PrettyMethod(method) << " " << code_size;
62        CHECK_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size));
63      } else {
64        const void* portable_oat_code = oat_method.GetPortableCode();
65        EXPECT_TRUE(portable_oat_code != nullptr) << PrettyMethod(method);
66        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U);
67        EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
68        EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
69        uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(portable_oat_code), 2);
70        portable_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
71        const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode();
72        EXPECT_TRUE(portable_code != nullptr);
73        size_t code_size = portable_code->size() * sizeof(portable_code[0]);
74        EXPECT_EQ(0, memcmp(quick_oat_code, &portable_code[0], code_size))
75            << PrettyMethod(method) << " " << code_size;
76        CHECK_EQ(0, memcmp(quick_oat_code, &portable_code[0], code_size));
77      }
78    }
79  }
80};
81
82TEST_F(OatTest, WriteRead) {
83  TimingLogger timings("CommonTest::WriteRead", false, false);
84  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
85
86  // TODO: make selectable.
87  CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
88  InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
89
90  InstructionSetFeatures insn_features;
91  verification_results_.reset(new VerificationResults);
92  method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
93  callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
94  timer_.reset(new CumulativeLogger("Compilation times"));
95  compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
96                                            method_inliner_map_.get(),
97                                            compiler_backend, insn_set,
98                                            insn_features, false, NULL, 2, true, true,
99                                            timer_.get()));
100  jobject class_loader = NULL;
101  if (kCompile) {
102    TimingLogger timings("OatTest::WriteRead", false, false);
103    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
104  }
105
106  ScopedObjectAccess soa(Thread::Current());
107  ScratchFile tmp;
108  OatWriter oat_writer(class_linker->GetBootClassPath(),
109                       42U,
110                       4096U,
111                       "lue.art",
112                       compiler_driver_.get(),
113                       &timings);
114  bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
115                                            !kIsTargetBuild,
116                                            class_linker->GetBootClassPath(),
117                                            oat_writer,
118                                            tmp.GetFile());
119  ASSERT_TRUE(success);
120
121  if (kCompile) {  // OatWriter strips the code, regenerate to compare
122    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
123  }
124  std::string error_msg;
125  UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false,
126                                            &error_msg));
127  ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
128  const OatHeader& oat_header = oat_file->GetOatHeader();
129  ASSERT_TRUE(oat_header.IsValid());
130  ASSERT_EQ(1U, oat_header.GetDexFileCount());  // core
131  ASSERT_EQ(42U, oat_header.GetImageFileLocationOatChecksum());
132  ASSERT_EQ(4096U, oat_header.GetImageFileLocationOatDataBegin());
133  ASSERT_EQ("lue.art", oat_header.GetImageFileLocation());
134
135  const DexFile* dex_file = java_lang_dex_file_;
136  uint32_t dex_file_checksum = dex_file->GetLocationChecksum();
137  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file->GetLocation().c_str(),
138                                                                    &dex_file_checksum);
139  ASSERT_TRUE(oat_dex_file != nullptr);
140  CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
141  for (size_t i = 0; i < dex_file->NumClassDefs(); i++) {
142    const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
143    const byte* class_data = dex_file->GetClassData(class_def);
144    size_t num_virtual_methods = 0;
145    if (class_data != NULL) {
146      ClassDataItemIterator it(*dex_file, class_data);
147      num_virtual_methods = it.NumVirtualMethods();
148    }
149    const char* descriptor = dex_file->GetClassDescriptor(class_def);
150    SirtRef<mirror::ClassLoader> loader(Thread::Current(), nullptr);
151    mirror::Class* klass = class_linker->FindClass(descriptor, loader);
152
153    UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(i));
154    CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class->GetStatus()) << descriptor;
155    CHECK_EQ(kCompile ? OatClassType::kOatClassAllCompiled : OatClassType::kOatClassNoneCompiled,
156             oat_class->GetType()) << descriptor;
157
158    size_t method_index = 0;
159    for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
160      CheckMethod(klass->GetDirectMethod(i),
161                  oat_class->GetOatMethod(method_index), dex_file);
162    }
163    for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
164      CheckMethod(klass->GetVirtualMethod(i),
165                  oat_class->GetOatMethod(method_index), dex_file);
166    }
167  }
168}
169
170TEST_F(OatTest, OatHeaderSizeCheck) {
171  // If this test is failing and you have to update these constants,
172  // it is time to update OatHeader::kOatVersion
173  EXPECT_EQ(76U, sizeof(OatHeader));
174  EXPECT_EQ(28U, sizeof(OatMethodOffsets));
175}
176
177TEST_F(OatTest, OatHeaderIsValid) {
178    InstructionSet instruction_set = kX86;
179    InstructionSetFeatures instruction_set_features;
180    std::vector<const DexFile*> dex_files;
181    uint32_t image_file_location_oat_checksum = 0;
182    uint32_t image_file_location_oat_begin = 0;
183    const std::string image_file_location;
184    OatHeader oat_header(instruction_set,
185                         instruction_set_features,
186                         &dex_files,
187                         image_file_location_oat_checksum,
188                         image_file_location_oat_begin,
189                         image_file_location);
190    ASSERT_TRUE(oat_header.IsValid());
191
192    char* magic = const_cast<char*>(oat_header.GetMagic());
193    strcpy(magic, "");  // bad magic
194    ASSERT_FALSE(oat_header.IsValid());
195    strcpy(magic, "oat\n000");  // bad version
196    ASSERT_FALSE(oat_header.IsValid());
197}
198
199}  // namespace art
200