oatdump.cc revision 95ba0dc516531776813c426e85ce868ead564a7b
12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/*
22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2011 The Android Open Source Project
32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * you may not use this file except in compliance with the License.
62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * You may obtain a copy of the License at
72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Unless required by applicable law or agreed to in writing, software
112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * See the License for the specific language governing permissions and
142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * limitations under the License.
152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes */
1678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include <stdio.h>
1878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include <stdlib.h>
1978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
2027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#include <fstream>
2127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#include <iostream>
22e5448b5a12003b405b22cde3b94f962ab4888a87Elliott Hughes#include <map>
2378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include <string>
2478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include <vector>
2578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
2678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include "class_linker.h"
273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers#include "context.h"
28e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes#include "dex_instruction.h"
293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers#include "dex_verifier.h"
303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers#include "disassembler.h"
31916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom#include "file.h"
3278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include "image.h"
336d4d9fcb4f01e287ee29e81cd1c941ee5d11d379Ian Rogers#include "object_utils.h"
34e5448b5a12003b405b22cde3b94f962ab4888a87Elliott Hughes#include "os.h"
3578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include "runtime.h"
3678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include "space.h"
3778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom#include "stringpiece.h"
3878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
3978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstromnamespace art {
4078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
4178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstromstatic void usage() {
4278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  fprintf(stderr,
4378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom          "Usage: oatdump [options] ...\n"
4429e7ac74a3f9aec192099fec381baadaa55730adBrian Carlstrom          "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art --host-prefix=$ANDROID_PRODUCT_OUT\n"
4529e7ac74a3f9aec192099fec381baadaa55730adBrian Carlstrom          "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
4678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom          "\n");
4778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  fprintf(stderr,
48a6cc893c4b142cd410fc956963b6f5a014e983adBrian Carlstrom          "  --oat-file=<file.oat>: specifies an input oat filename.\n"
4929e7ac74a3f9aec192099fec381baadaa55730adBrian Carlstrom          "      Example: --image=/system/framework/boot.oat\n"
50aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom          "\n");
51aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  fprintf(stderr,
52aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom          "  --image=<file.art>: specifies an input image filename.\n"
5329e7ac74a3f9aec192099fec381baadaa55730adBrian Carlstrom          "      Example: --image=/system/framework/boot.art\n"
54e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom          "\n");
5578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  fprintf(stderr,
56e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom          "  --boot-image=<file.art>: provide the image file for the boot class path.\n"
5729e7ac74a3f9aec192099fec381baadaa55730adBrian Carlstrom          "      Example: --boot-image=/system/framework/boot.art\n"
58e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom          "\n");
59e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  fprintf(stderr,
6058ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom          "  --host-prefix may be used to translate host paths to target paths during\n"
6158ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom          "      cross compilation.\n"
6258ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom          "      Example: --host-prefix=out/target/product/crespo\n"
63fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom          "      Default: $ANDROID_PRODUCT_OUT\n"
6478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom          "\n");
6527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  fprintf(stderr,
6627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom          "  --output=<file> may be used to send the output to a file.\n"
6727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom          "      Example: --output=/tmp/oatdump.txt\n"
6827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom          "\n");
6978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  exit(EXIT_FAILURE);
7078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom}
7178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
72ff1ed4770bf7ff024a807b9f909b1a26abb78341Ian Rogersconst char* image_roots_descriptions_[] = {
7378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  "kJniStubArray",
74e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  "kAbstractMethodErrorStubArray",
75ad25ac568407ceb14334e8551dd1c4dd0fd6993cIan Rogers  "kStaticResolutionStubArray",
761cb0a1dfc32531c79a968aeac26ccb5525862497Ian Rogers  "kUnknownMethodResolutionStubArray",
771984651929744dd603fd082e23eacd877b9bc177Ian Rogers  "kResolutionMethod",
78e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  "kCalleeSaveMethod",
79aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  "kRefsOnlySaveMethod",
80aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  "kRefsAndArgsSaveMethod",
81e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  "kOatLocation",
8258ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  "kDexCaches",
8334f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom  "kClassRoots",
8478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom};
8578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
86e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughesclass OatDumper {
87aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom public:
883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  explicit OatDumper(const OatFile& oat_file) : oat_file_(oat_file),
89a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes      oat_dex_files_(oat_file.GetOatDexFiles()),
90a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes      disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet())) {
913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    AddAllOffsets();
923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void Dump(std::ostream& os) {
953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    const OatHeader& oat_header = oat_file_.GetOatHeader();
96aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
97aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << "MAGIC:\n";
98aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << oat_header.GetMagic() << "\n\n";
99aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
100aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << "CHECKSUM:\n";
101ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
102aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
103a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes    os << "INSTRUCTION SET:\n";
104a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes    os << oat_header.GetInstructionSet() << "\n\n";
105a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes
106aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << "DEX FILE COUNT:\n";
107aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << oat_header.GetDexFileCount() << "\n\n";
108aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
109aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << "EXECUTABLE OFFSET:\n";
110ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("0x%08x\n\n", oat_header.GetExecutableOffset());
111aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
11230fab40ee5a07af6b8c3b6b0e9438071695a57f4Ian Rogers    os << "BEGIN:\n";
1133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
114aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
11530fab40ee5a07af6b8c3b6b0e9438071695a57f4Ian Rogers    os << "END:\n";
1163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
117aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
118aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << std::flush;
119aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
1203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < oat_dex_files_.size(); i++) {
1213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
1223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      CHECK(oat_dex_file != NULL);
1233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatDexFile(os, *oat_dex_file);
1243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
1253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
1263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
1273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  size_t ComputeSize(const void* oat_data) {
1283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (reinterpret_cast<const byte*>(oat_data) < oat_file_.Begin() ||
1293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        reinterpret_cast<const byte*>(oat_data) > oat_file_.End()) {
1303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return 0;  // Address not in oat file
1313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
1323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint32_t begin_offset = reinterpret_cast<size_t>(oat_data) -
1333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                            reinterpret_cast<size_t>(oat_file_.Begin());
1343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    typedef std::set<uint32_t>::iterator It;
1353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    It it = offsets_.upper_bound(begin_offset);
1363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    CHECK(it != offsets_.end());
1373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint32_t end_offset = *it;
1383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return end_offset - begin_offset;
1393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
140e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
1413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const void* GetOatCode(Method* m) {
1423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    MethodHelper mh(m);
1433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < oat_dex_files_.size(); i++) {
1443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
145aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      CHECK(oat_dex_file != NULL);
1463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
1473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (dex_file.get() != NULL) {
1483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        uint32_t class_def_index;
1493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool found = dex_file->FindClassDefIndex(mh.GetDeclaringClassDescriptor(), class_def_index);
1503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (found) {
1513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index);
1523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          CHECK(oat_class != NULL);
1533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          size_t method_index = m->GetMethodIndex();
1543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          return oat_class->GetOatMethod(method_index).GetCode();
1553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
1563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
157aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
1583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return NULL;
159aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
160aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
161aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom private:
1623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void AddAllOffsets() {
163e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // We don't know the length of the code for each method, but we need to know where to stop
164e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // when disassembling. What we do know is that a region of code will be followed by some other
165e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // region, so if we keep a sorted sequence of the start of each region, we can infer the length
166e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // of a piece of code by using upper_bound to find the start of the next region.
1673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < oat_dex_files_.size(); i++) {
1683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
169e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      CHECK(oat_dex_file != NULL);
170e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
171e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      if (dex_file.get() == NULL) {
1723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        continue;
173e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      }
1743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      offsets_.insert(reinterpret_cast<uint32_t>(&dex_file->GetHeader()));
175e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
176e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
177e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
178e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        const byte* class_data = dex_file->GetClassData(class_def);
179e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        if (class_data != NULL) {
180e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          ClassDataItemIterator it(*dex_file, class_data);
181e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          SkipAllFields(it);
182e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          uint32_t class_method_index = 0;
183e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          while (it.HasNextDirectMethod()) {
184e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            AddOffsets(oat_class->GetOatMethod(class_method_index++));
185e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            it.Next();
186e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          }
187e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          while (it.HasNextVirtualMethod()) {
188e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            AddOffsets(oat_class->GetOatMethod(class_method_index++));
189e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            it.Next();
190e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          }
191e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        }
192e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      }
193e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
194e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
195e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // If the last thing in the file is code for a method, there won't be an offset for the "next"
196e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // thing. Instead of having a special case in the upper_bound code, let's just add an entry
197e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // for the end of the file.
1983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    offsets_.insert(static_cast<uint32_t>(oat_file_.End() - oat_file_.Begin()));
199e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
200e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
201e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  void AddOffsets(const OatFile::OatMethod& oat_method) {
20295ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    uint32_t code_offset = oat_method.GetCodeOffset();
20395ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
20495ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom      code_offset &= ~0x1;
20595ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    }
20695ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    offsets_.insert(code_offset);
207e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetMappingTableOffset());
208e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetVmapTableOffset());
209e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetGcMapOffset());
210e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetInvokeStubOffset());
211e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
212e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
2133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
214aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << "OAT DEX FILE:\n";
215a004aa933a58428489e42d77f707c2b063b73747Brian Carlstrom    os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
216ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
217a004aa933a58428489e42d77f707c2b063b73747Brian Carlstrom    UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile());
218a004aa933a58428489e42d77f707c2b063b73747Brian Carlstrom    if (dex_file.get() == NULL) {
219aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      os << "NOT FOUND\n\n";
220aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      return;
221aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
222aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
223aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
224aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      const char* descriptor = dex_file->GetClassDescriptor(class_def);
225aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
226aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      CHECK(oat_class.get() != NULL);
227ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes      os << StringPrintf("%zd: %s (type_idx=%d) (", class_def_index, descriptor, class_def.class_idx_)
228e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom         << oat_class->GetStatus() << ")\n";
2293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatClass(os, *oat_class.get(), *(dex_file.get()), class_def);
230aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
231aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
232aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << std::flush;
233aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
234aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
235e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  static void SkipAllFields(ClassDataItemIterator& it) {
2360571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextStaticField()) {
2370571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
238aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
2390571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextInstanceField()) {
2400571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
241aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
242e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
243aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
2443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
2453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    const DexFile::ClassDef& class_def) {
246e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const byte* class_data = dex_file.GetClassData(class_def);
247e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    if (class_data == NULL) {  // empty class such as a marker interface?
248e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      return;
249e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
250e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    ClassDataItemIterator it(dex_file, class_data);
251e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    SkipAllFields(it);
252e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
253e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    uint32_t class_method_index = 0;
2540571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextDirectMethod()) {
255e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
2563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatMethod(os, class_method_index, oat_method, dex_file,
2573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    it.GetMemberIndex(), it.GetMethodCodeItem());
258e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      class_method_index++;
2590571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
260aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
2610571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextVirtualMethod()) {
262e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
2633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatMethod(os, class_method_index, oat_method, dex_file,
2643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    it.GetMemberIndex(), it.GetMethodCodeItem());
265e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      class_method_index++;
2660571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
267aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
2680571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    DCHECK(!it.HasNext());
269aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << std::flush;
270aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
271e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
2723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpOatMethod(std::ostream& os, uint32_t class_method_index,
273e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes                     const OatFile::OatMethod& oat_method, const DexFile& dex_file,
274e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes                     uint32_t dex_method_idx, const DexFile::CodeItem* code_item) {
275e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
276aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    const char* name = dex_file.GetMethodName(method_id);
277955724179c6c739524f610023287f56b24dc31deElliott Hughes    std::string signature(dex_file.GetMethodSignature(method_id));
278e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    os << StringPrintf("\t%d: %s %s (dex_method_idx=%d)\n",
279e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes                       class_method_index, name, signature.c_str(), dex_method_idx);
280ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tcode: %p (offset=0x%08x)\n",
281ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetCode(), oat_method.GetCodeOffset());
282ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes    os << StringPrintf("\t\tframe_size_in_bytes: %zd\n",
283ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetFrameSizeInBytes());
2843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << StringPrintf("\t\tcore_spill_mask: 0x%08x",
285ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetCoreSpillMask());
2863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpSpillMask(os, oat_method.GetCoreSpillMask(), false);
2873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << StringPrintf("\n\t\tfp_spill_mask: 0x%08x",
288ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetFpSpillMask());
2893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpSpillMask(os, oat_method.GetFpSpillMask(), true);
2903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << StringPrintf("\n\t\tmapping_table: %p (offset=0x%08x)\n",
291ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
2923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpMappingTable(os, oat_method);
293ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tvmap_table: %p (offset=0x%08x)\n",
294ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
2953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpVmap(os, oat_method.GetVmapTable(), oat_method.GetCoreSpillMask(),
2963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers             oat_method.GetFpSpillMask());
297ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tgc_map: %p (offset=0x%08x)\n",
298e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom                       oat_method.GetGcMap(), oat_method.GetGcMapOffset());
2993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpGcMap(os, oat_method.GetGcMap());
300ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tinvoke_stub: %p (offset=0x%08x)\n",
301ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
3023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "\t\tCODE:\n";
3033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpCode(os, oat_method.GetCode(), oat_method.GetMappingTable(), dex_file, code_item);
3043a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "\t\tINVOKE STUB:\n";
3053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpCode(os, reinterpret_cast<const void*>(oat_method.GetInvokeStub()), NULL, dex_file, NULL);
3063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
3073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
3083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
3093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (spill_mask == 0) {
3103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
3113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << " (";
3133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < 32; i++) {
3143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if ((spill_mask & (1 << i)) != 0) {
3153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (is_float) {
3163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          os << "fr" << i;
3173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        } else {
3183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          os << "r" << i;
3193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        spill_mask ^= 1 << i;  // clear bit
3213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (spill_mask != 0) {
3223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          os << ", ";
3233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        } else {
3243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
3253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << ")";
3293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
3303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
3313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpVmap(std::ostream& os, const uint16_t* raw_table, uint32_t core_spill_mask,
3323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                uint32_t fp_spill_mask) {
3333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (raw_table == NULL) {
3343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
3353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    const VmapTable vmap_table(raw_table);
3373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    bool first = true;
3383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "\t\t\t";
3393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < vmap_table.size(); i++) {
3403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint16_t dex_reg = vmap_table[i];
3413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t matches = 0;
3423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t spill_shifts = 0;
3433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint32_t spill_mask = core_spill_mask;
3443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      bool processing_fp = false;
3453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      while (matches != (i + 1)) {
3463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (spill_mask == 0) {
3473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          CHECK(!processing_fp);
3483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          spill_mask = fp_spill_mask;
3493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          processing_fp = true;
3503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        matches += spill_mask & 1;  // Add 1 if the low bit is set
3523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        spill_mask >>= 1;
3533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        spill_shifts++;
3543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t arm_reg = spill_shifts - 1;  // wind back one as we want the last match
3563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << (first ? "v" : ", v")  << dex_reg;
3573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (arm_reg < 16) {
3583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "/r" << arm_reg;
3593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      } else {
3603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "/fr" << (arm_reg - 16);
3613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (first) {
3633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        first = false;
3643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << std::endl;
3673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
3683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
3693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpGcMap(std::ostream& os, const uint8_t* gc_map_raw) {
3703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (gc_map_raw == NULL) {
3713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
3723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint32_t gc_map_length = (gc_map_raw[0] << 24) | (gc_map_raw[1] << 16) |
3743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                             (gc_map_raw[2] << 8) | (gc_map_raw[3] << 0);
3753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    verifier::PcToReferenceMap map(gc_map_raw + sizeof(uint32_t), gc_map_length);
3763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t entry = 0; entry < map.NumEntries(); entry++) {
3773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\t\t\t0x%04x", map.GetPC(entry));
3783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t num_regs = map.RegWidth() * 8;
3793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* reg_bitmap = map.GetBitMap(entry);
3803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      bool first = true;
3813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t reg = 0; reg < num_regs; reg++) {
3823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
3833a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (first) {
3843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os << "  v" << reg;
3853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            first = false;
3863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          } else {
3873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os << ", v" << reg;
3883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
3893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl;
3923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
393aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
394e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
3953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
396e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const uint32_t* raw_table = oat_method.GetMappingTable();
397e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const void* code = oat_method.GetCode();
398e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    if (raw_table == NULL || code == NULL) {
399e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      return;
400e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
401e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
402e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    uint32_t length = *raw_table;
403e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    ++raw_table;
404e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
4053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "\t\t{";
406e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    for (size_t i = 0; i < length; i += 2) {
4073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) + raw_table[i];
408e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      uint32_t dex_pc = raw_table[i + 1];
4093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("%p -> 0x%04x", native_pc, dex_pc);
4103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (i + 2 < length) {
4113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << ", ";
4123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
4133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
4143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "}" << std::endl << std::flush;
4153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
4163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpCode(std::ostream& os, const void* code, const uint32_t* raw_mapping_table,
4183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                const DexFile& dex_file, const DexFile::CodeItem* code_item) {
4193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (code == NULL) {
4203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
4213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
4223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (raw_mapping_table == NULL) {
4243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // code but no mapping table is most likely caused by code created by the JNI compiler
4253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code);
4263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* oat_begin = reinterpret_cast<const uint8_t*>(oat_file_.Begin());
4273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint32_t last_offset = static_cast<uint32_t>(native_pc - oat_begin);
4283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      typedef std::set<uint32_t>::iterator It;
4303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      It it = offsets_.upper_bound(last_offset);
4313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      CHECK(it != offsets_.end());
4323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* end_native_pc = reinterpret_cast<const uint8_t*>(oat_begin) + *it;
4333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      CHECK(native_pc < end_native_pc);
4343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      disassembler_->Dump(os, native_pc, end_native_pc);
4363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
4373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
4383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint32_t length = *raw_mapping_table;
4403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    ++raw_mapping_table;
4413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < length; i += 2) {
4433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint32_t dex_pc = raw_mapping_table[i + 1];
444e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const Instruction* instruction = Instruction::At(&code_item->insns_[dex_pc]);
445e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      os << StringPrintf("\t\t0x%04x: %s\n", dex_pc, instruction->DumpString(&dex_file).c_str());
446e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
4473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) + raw_mapping_table[i];
448e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const uint8_t* end_native_pc = NULL;
449e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      if (i + 2 < length) {
4503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        end_native_pc = reinterpret_cast<const uint8_t*>(code) + raw_mapping_table[i + 2];
451e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      } else {
4523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        const uint8_t* oat_begin = reinterpret_cast<const uint8_t*>(oat_file_.Begin());
453e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        uint32_t last_offset = static_cast<uint32_t>(native_pc - oat_begin);
454e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
455e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        typedef std::set<uint32_t>::iterator It;
456ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes        It it = offsets_.upper_bound(last_offset);
457e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        CHECK(it != offsets_.end());
458e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        end_native_pc = reinterpret_cast<const uint8_t*>(oat_begin) + *it;
459e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      }
460ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes      CHECK(native_pc < end_native_pc);
4613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      disassembler_->Dump(os, native_pc, end_native_pc);
462e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
463e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
464e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
4653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const OatFile& oat_file_;
4663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  std::vector<const OatFile::OatDexFile*> oat_dex_files_;
467e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  std::set<uint32_t> offsets_;
4683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  UniquePtr<Disassembler> disassembler_;
469aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom};
470aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
4713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogersclass ImageDumper {
47227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom public:
4733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  explicit ImageDumper(std::ostream& os, const std::string& image_filename,
4743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       const std::string& host_prefix, Space& image_space,
4753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       const ImageHeader& image_header) : os_(os),
4763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       image_filename_(image_filename), host_prefix_(host_prefix),
4773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       image_space_(image_space), image_header_(image_header) {
4783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
47927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
4803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void Dump() {
4813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "MAGIC:\n";
4823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << image_header_.GetMagic() << "\n\n";
483e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom
4843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "IMAGE BEGIN:\n";
4853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
486aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
4873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT CHECKSUM:\n";
4883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
489916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
4903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT BEGIN:\n";
4913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetOatBegin()) << "\n\n";
492aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
4933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT END:\n";
4943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetOatEnd()) << "\n\n";
4953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "ROOTS:\n";
4973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
498418d20fc407052d4152157f61e7453359f902383Elliott Hughes    CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
49927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
50027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
50134f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom      const char* image_root_description = image_roots_descriptions_[i];
5023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      Object* image_root_object = image_header_.GetImageRoot(image_root);
5033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os_ << StringPrintf("%s: %p\n", image_root_description, image_root_object);
50434f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom      if (image_root_object->IsObjectArray()) {
50534f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        // TODO: replace down_cast with AsObjectArray (g++ currently has a problem with this)
50634f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        ObjectArray<Object>* image_root_object_array
50734f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom            = down_cast<ObjectArray<Object>*>(image_root_object);
50834f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        //  = image_root_object->AsObjectArray<Object>();
50934f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        for (int i = 0; i < image_root_object_array->GetLength(); i++) {
510d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          Object* value = image_root_object_array->Get(i);
511d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          if (value != NULL) {
5123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os_ << "\t" << i << ": ";
513d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            std::string summary;
514d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            PrettyObjectValue(summary, value->GetClass(), value);
5153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os_ << summary;
516d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          } else {
5173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os_ << StringPrintf("\t%d: null\n", i);
518d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          }
51934f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        }
52034f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom      }
52127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    }
5223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
52327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
524aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
5253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    Object* oat_location_object = image_header_.GetImageRoot(ImageHeader::kOatLocation);
5263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::string oat_location(oat_location_object->AsString()->ToModifiedUtf8());
5273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (!host_prefix_.empty()) {
5283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      oat_location = host_prefix_ + oat_location;
5293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os_ << " (" << oat_location << ")";
530aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
531ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom    const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location);
532aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    if (oat_file == NULL) {
5333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os_ << "OAT FILE NOT FOUND: " << oat_location << std::endl << std::flush;
534aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      return;
535aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
536aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
5373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.oat_file_bytes = oat_file->Size();
53878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
5393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    oat_dumper_.reset(new OatDumper(*oat_file));
5403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OBJECTS:\n" << std::flush;
5423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    HeapBitmap* heap_bitmap = Heap::GetLiveBits();
5433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DCHECK(heap_bitmap != NULL);
5443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    heap_bitmap->Walk(ImageDumper::Callback, this);
5453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
5463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "STATS:\n" << std::flush;
5483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    UniquePtr<File> file(OS::OpenFile(image_filename_.c_str(), false));
5493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.file_bytes = file->Length();
5503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t header_bytes = sizeof(ImageHeader);
5513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.header_bytes = header_bytes;
5523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
5533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.alignment_bytes += alignment_bytes;
5543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.Dump(os_);
5553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
55627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
5573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << std::flush;
5583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT LOCATION:\n" << std::flush;
5603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << oat_location;
5613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
5623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    oat_dumper_->Dump(os_);
5633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
564d1bb4f6b7c8dda429f61937cd42f3a0b7367c271Elliott Hughes
5653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers private:
56627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
567d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  static void PrettyObjectValue(std::string& summary, Class* type, Object* value) {
568d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    CHECK(type != NULL);
569d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (value == NULL) {
570d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "null   %s\n", PrettyDescriptor(type).c_str());
571d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsStringClass()) {
572d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      String* string = value->AsString();
573d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   String: \"%s\"\n", string, string->ToModifiedUtf8().c_str());
574d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (value->IsClass()) {
575d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Class* klass = value->AsClass();
576d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
577d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (value->IsField()) {
578d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Field* field = value->AsField();
579d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   Field: %s\n", field, PrettyField(field).c_str());
580d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (value->IsMethod()) {
581d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Method* method = value->AsMethod();
582d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   Method: %s\n", method, PrettyMethod(method).c_str());
583d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else {
584d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   %s\n", value, PrettyDescriptor(type).c_str());
585d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
586d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  }
587d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
588d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  static void PrintField(std::string& summary, Field* field, Object* obj) {
589d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    FieldHelper fh(field);
590d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    Class* type = fh.GetType();
591d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    StringAppendF(&summary, "\t%s: ", fh.GetName());
592d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (type->IsPrimitiveLong()) {
593d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%lld (0x%llx)\n", field->Get64(obj), field->Get64(obj));
594d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsPrimitiveDouble()) {
595d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
596d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsPrimitiveFloat()) {
597d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
598d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsPrimitive()){
599d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
600d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else {
601d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Object* value = field->GetObj(obj);
602d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      PrettyObjectValue(summary, type, value);
603d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
604d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  }
605d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
606d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  static void DumpFields(std::string& summary, Object* obj, Class* klass) {
607d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    Class* super = klass->GetSuperClass();
608d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (super != NULL) {
609d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      DumpFields(summary, obj, super);
610d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
611d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    ObjectArray<Field>* fields = klass->GetIFields();
612d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (fields != NULL) {
613d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      for (int32_t i = 0; i < fields->GetLength(); i++) {
614d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        Field* field = fields->Get(i);
615d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        PrintField(summary, field, obj);
616d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      }
617d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
618d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  }
619d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
6203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  bool InDumpSpace(const Object* object) {
6213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return image_space_.Contains(object);
6223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers }
6233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
6243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const void* GetOatCode(Method* m) {
6253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    Runtime* runtime = Runtime::Current();
6263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    const void* code = m->GetCode();
627fb6adba0d5d5505610fbd325e7911db700a2f1e8Ian Rogers    if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
6283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      code = oat_dumper_->GetOatCode(m);
6293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
6303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return code;
6313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
6323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
63378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  static void Callback(Object* obj, void* arg) {
63478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    DCHECK(obj != NULL);
63578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    DCHECK(arg != NULL);
6363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
63778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    if (!state->InDumpSpace(obj)) {
63878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      return;
63978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
640916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
641916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t object_bytes = obj->SizeOf();
642916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
643916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    state->stats_.object_bytes += object_bytes;
644916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    state->stats_.alignment_bytes += alignment_bytes;
645916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
64678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    std::string summary;
647d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    Class* obj_class = obj->GetClass();
648d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (obj_class->IsArrayClass()) {
649d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
650d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    obj->AsArray()->GetLength());
651d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsClass()) {
65278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      Class* klass = obj->AsClass();
653d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.Class \"%s\" (", obj,
654d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    PrettyDescriptor(klass).c_str());
6553b6baaa203fa63f1522b2172a1645f90412afdaeElliott Hughes      std::ostringstream ss;
656d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      ss << klass->GetStatus() << ")\n";
657e10b6974d54f38001aee7bec518d45a7d4fb64c1Brian Carlstrom      summary += ss.str();
65878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    } else if (obj->IsField()) {
659d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.reflect.Field %s\n", obj,
660d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    PrettyField(obj->AsField()).c_str());
661d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsMethod()) {
662d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.reflect.Method %s\n", obj,
663d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    PrettyMethod(obj->AsMethod()).c_str());
664d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj_class->IsStringClass()) {
665d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.String \"%s\"\n", obj,
666d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    obj->AsString()->ToModifiedUtf8().c_str());
66778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    } else {
668d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
66978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
670d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    DumpFields(summary, obj, obj_class);
671d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (obj->IsObjectArray()) {
672d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      ObjectArray<Object>* obj_array = obj->AsObjectArray<Object>();
673d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      int32_t length = obj_array->GetLength();
674d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      for (int32_t i = 0; i < length; i++) {
675d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        Object* value = obj_array->Get(i);
676d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        size_t run = 0;
677d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        for (int32_t j = i + 1; j < length; j++) {
678d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          if (value == obj_array->Get(j)) {
679d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            run++;
680d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          } else {
681d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            break;
682d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          }
683d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        }
684d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        if (run == 0) {
685d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          StringAppendF(&summary, "\t%d: ", i);
68678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom        } else {
687c1051ae94c5bd45367152a603f3946a933ad91faElliott Hughes          StringAppendF(&summary, "\t%d to %zd: ", i, i + run);
688d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          i = i + run;
68978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom        }
690d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        Class* value_class = value == NULL ? obj_class->GetComponentType() : value->GetClass();
691d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        PrettyObjectValue(summary, value_class, value);
692d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      }
693d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsClass()) {
694d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      ObjectArray<Field>* sfields = obj->AsClass()->GetSFields();
695d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      if (sfields != NULL) {
696d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        summary += "\t\tSTATICS:\n";
697d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        for (int32_t i = 0; i < sfields->GetLength(); i++) {
698d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          Field* field = sfields->Get(i);
699d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          PrintField(summary, field, NULL);
700d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        }
701d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      }
702d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsMethod()) {
703d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Method* method = obj->AsMethod();
704d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      if (method->IsNative()) {
705d81871cbbaa34c649e488f94f61a981db33123e5Ian Rogers        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
706e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
7073320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
7083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first_occurrence;
7093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t invoke_stub_size = state->ComputeOatSize(
7103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            reinterpret_cast<const void*>(method->GetInvokeStub()), &first_occurrence);
7113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurrence) {
7123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.managed_to_native_code_bytes += invoke_stub_size;
7133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        const void* oat_code = state->GetOatCode(method);
7153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t code_size = state->ComputeOatSize(oat_code, &first_occurrence);
7163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurrence) {
7173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.native_to_managed_code_bytes += code_size;
7183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (oat_code != method->GetCode()) {
7203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          StringAppendF(&summary, "\t\tOAT CODE: %p\n", oat_code);
7213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7221984651929744dd603fd082e23eacd877b9bc177Ian Rogers      } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
7231984651929744dd603fd082e23eacd877b9bc177Ian Rogers          method->IsResolutionMethod()) {
724d81871cbbaa34c649e488f94f61a981db33123e5Ian Rogers        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
725e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
7263320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
727916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      } else {
728e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK(method->GetGcMap() != NULL) << PrettyMethod(method);
729e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK_NE(0U, method->GetGcMapLength()) << PrettyMethod(method);
730916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
7316d4d9fcb4f01e287ee29e81cd1c941ee5d11d379Ian Rogers        const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
732d81871cbbaa34c649e488f94f61a981db33123e5Ian Rogers        size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
733916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        state->stats_.dex_instruction_bytes += dex_instruction_bytes;
734e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom
7353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first_occurance;
7363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t gc_map_bytes = state->ComputeOatSize(method->GetGcMapRaw(), &first_occurance);
7373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.gc_map_bytes += gc_map_bytes;
7393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t pc_mapping_table_bytes =
7423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            state->ComputeOatSize(method->GetMappingTableRaw(), &first_occurance);
7433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
7453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t vmap_table_bytes =
7483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            state->ComputeOatSize(method->GetVmapTableRaw(), &first_occurance);
7493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.vmap_table_bytes += vmap_table_bytes;
7513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t invoke_stub_size = state->ComputeOatSize(
7543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            reinterpret_cast<const void*>(method->GetInvokeStub()), &first_occurance);
7553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.native_to_managed_code_bytes += invoke_stub_size;
7573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        const void* oat_code = state->GetOatCode(method);
7593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t code_size = state->ComputeOatSize(oat_code, &first_occurance);
7603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.managed_code_bytes += code_size;
7623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        state->stats_.managed_code_bytes_ignoring_deduplication += code_size;
7643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (oat_code != method->GetCode()) {
7663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          StringAppendF(&summary, "\t\tOAT CODE: %p\n", oat_code);
7673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
768d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        StringAppendF(&summary, "\t\tSIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
7693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                      dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
7703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
7723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            vmap_table_bytes + invoke_stub_size + code_size + object_bytes;
7733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        double expansion =
7753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            static_cast<double>(code_size) / static_cast<double>(dex_instruction_bytes);
7763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        state->stats_.ComputeOutliers(total_size, expansion, method);
77778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      }
77878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
779d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    std::string descriptor(ClassHelper(obj_class).GetDescriptor());
780d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    state->stats_.descriptor_to_bytes[descriptor] += object_bytes;
781d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    state->stats_.descriptor_to_count[descriptor] += 1;
782d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
78327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    state->os_ << summary << std::flush;
78478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
78527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
7863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  std::set<const void*> already_seen_;
7873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // Compute the size of the given data within the oat file and whether this is the first time
7883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // this data has been requested
7893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  size_t ComputeOatSize(const void* oat_data, bool* first_occurance) {
7903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (already_seen_.count(oat_data) == 0) {
7913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      *first_occurance = true;
7923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      already_seen_.insert(oat_data);
7933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    } else {
7943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      *first_occurance = false;
7953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
7963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return oat_dumper_->ComputeSize(oat_data);
79727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  }
798916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
799916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom public:
800916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom  struct Stats {
8013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t oat_file_bytes;
802916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t file_bytes;
803916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
804916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t header_bytes;
805916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t object_bytes;
806916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t alignment_bytes;
807916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
808916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t managed_code_bytes;
8093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t managed_code_bytes_ignoring_deduplication;
810916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t managed_to_native_code_bytes;
811916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t native_to_managed_code_bytes;
812916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t gc_map_bytes;
814916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t pc_mapping_table_bytes;
8153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t vmap_table_bytes;
816916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
817916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t dex_instruction_bytes;
818916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::vector<Method*> method_outlier;
8203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::vector<size_t> method_outlier_size;
8213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::vector<double> method_outlier_expansion;
8223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
8233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    explicit Stats()
8243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        : oat_file_bytes(0),
8253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          file_bytes(0),
826916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          header_bytes(0),
827916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          object_bytes(0),
828916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          alignment_bytes(0),
829916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          managed_code_bytes(0),
8303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          managed_code_bytes_ignoring_deduplication(0),
831916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          managed_to_native_code_bytes(0),
832916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          native_to_managed_code_bytes(0),
8333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          gc_map_bytes(0),
834916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          pc_mapping_table_bytes(0),
8353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          vmap_table_bytes(0),
836916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          dex_instruction_bytes(0) {}
837916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
838e5448b5a12003b405b22cde3b94f962ab4888a87Elliott Hughes    typedef std::map<std::string, size_t> TableBytes;
839916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    TableBytes descriptor_to_bytes;
840916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
841e5448b5a12003b405b22cde3b94f962ab4888a87Elliott Hughes    typedef std::map<std::string, size_t> TableCount;
842916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    TableCount descriptor_to_count;
843916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    double PercentOfOatBytes(size_t size) {
8453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
8463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
8473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
848916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    double PercentOfFileBytes(size_t size) {
849916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
850916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    }
851916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
852916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    double PercentOfObjectBytes(size_t size) {
853916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
854916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    }
855916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    void ComputeOutliers(size_t total_size, double expansion, Method* method) {
8573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      method_outlier_size.push_back(total_size);
8583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      method_outlier_expansion.push_back(expansion);
8593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      method_outlier.push_back(method);
8603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
8613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
8623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    void DumpOutliers(std::ostream& os) {
8633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_sizes = 0;
8643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_sizes_squared = 0;
8653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_expansion = 0;
8663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_expansion_squared = 0;
8673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t n = method_outlier_size.size();
8683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t i = 0; i < n; i++) {
8693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t cur_size = method_outlier_size[i];
8703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_sizes += cur_size;
8713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_sizes_squared += cur_size * cur_size;
8723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        double cur_expansion = method_outlier_expansion[i];
8733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_expansion += cur_expansion;
8743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_expansion_squared += cur_expansion * cur_expansion;
8753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
8763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t size_mean = sum_of_sizes / n;
8773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
8783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      double expansion_mean = sum_of_expansion / n;
8793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      double expansion_variance =
8803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
8813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
8823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Dump methods whose size is a certain number of standard deviations from the mean
8833a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t dumped_values = 0;
8843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t skipped_values = 0;
8853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
8863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t cur_size_variance = i * i * size_variance;
8873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first = true;
8883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        for (size_t j = 0; j < n; j++) {
8893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          size_t cur_size = method_outlier_size[j];
8903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (cur_size > size_mean) {
8913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            size_t cur_var = cur_size - size_mean;
8923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            cur_var = cur_var * cur_var;
8933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            if (cur_var > cur_size_variance) {
8943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              if (dumped_values > 20) {
8953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (i == 1) {
8963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  skipped_values++;
8973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                } else {
8983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  i = 2;  // jump to counting for 1 standard deviation
8993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  break;
9003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              } else {
9023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (first) {
9033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  os << "\nBig methods (size > " << i << " standard deviations the norm):"
9043a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                     << std::endl;
9053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  first = false;
9063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                os << "\t" << PrettyMethod(method_outlier[j]) << " requires storage of "
9083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    << PrettySize(cur_size) << std::endl;
9093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                method_outlier_size[j] = 0;  // don't consider this method again
9103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                dumped_values++;
9113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              }
9123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            }
9133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
9143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
9153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (skipped_values > 0) {
9173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "\t... skipped " << skipped_values
9183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers           << " methods with size > 1 standard deviation from the norm" << std::endl;
9193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
9213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
9223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Dump methods whose expansion is a certain number of standard deviations from the mean
9233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      dumped_values = 0;
9243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      skipped_values = 0;
9253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
9263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        double cur_expansion_variance = i * i * expansion_variance;
9273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first = true;
9283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        for (size_t j = 0; j < n; j++) {
9293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          double cur_expansion = method_outlier_expansion[j];
9303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (cur_expansion > expansion_mean) {
9313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            size_t cur_var = cur_expansion - expansion_mean;
9323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            cur_var = cur_var * cur_var;
9333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            if (cur_var > cur_expansion_variance) {
9343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              if (dumped_values > 20) {
9353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (i == 1) {
9363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  skipped_values++;
9373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                } else {
9383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  i = 2;  // jump to counting for 1 standard deviation
9393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  break;
9403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              } else {
9423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (first) {
9433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  os << "\nLarge expansion methods (size > " << i
9443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                      << " standard deviations the norm):" << std::endl;
9453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  first = false;
9463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                os << "\t" << PrettyMethod(method_outlier[j]) << " expanded code by "
9483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    << cur_expansion << std::endl;
9493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                method_outlier_expansion[j] = 0.0;  // don't consider this method again
9503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                dumped_values++;
9513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              }
9523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            }
9533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
9543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
9553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (skipped_values > 0) {
9573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "\t... skipped " << skipped_values
9583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers           << " methods with expansion > 1 standard deviation from the norm" << std::endl;
9593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
9613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
9623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
963916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    void Dump(std::ostream& os) {
9643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << "\tart_file_bytes = " << PrettySize(file_bytes) << std::endl << std::endl
9653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << "\tart_file_bytes = header_bytes + object_bytes + alignment_bytes" << std::endl
9663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << StringPrintf("\theader_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
9673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tobject_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
9683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\talignment_bytes =  %8zd (%2.0f%% of art file bytes)\n",
9693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         header_bytes, PercentOfFileBytes(header_bytes),
9703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         object_bytes, PercentOfFileBytes(object_bytes),
9713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         alignment_bytes, PercentOfFileBytes(alignment_bytes))
9723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << std::endl << std::flush;
9733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
974916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      CHECK_EQ(file_bytes, header_bytes + object_bytes + alignment_bytes);
975916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
976916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      os << "\tobject_bytes = sum of descriptor_to_bytes values below:\n";
977916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      size_t object_bytes_total = 0;
978916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      typedef TableBytes::const_iterator It;  // TODO: C++0x auto
979916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      for (It it = descriptor_to_bytes.begin(), end = descriptor_to_bytes.end(); it != end; ++it) {
980955724179c6c739524f610023287f56b24dc31deElliott Hughes        const std::string& descriptor(it->first);
981916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        size_t bytes = it->second;
982916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        size_t count = descriptor_to_count[descriptor];
983916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        double average = static_cast<double>(bytes) / static_cast<double>(count);
984916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        double percent = PercentOfObjectBytes(bytes);
985ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes        os << StringPrintf("\t%32s %8zd bytes %6zd instances "
986916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom                           "(%3.0f bytes/instance) %2.0f%% of object_bytes\n",
987916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom                           descriptor.c_str(), bytes, count,
988916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom                           average, percent);
989916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
990916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        object_bytes_total += bytes;
991916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      }
9923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
993916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      CHECK_EQ(object_bytes, object_bytes_total);
994916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
9953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\tmanaged_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
9963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tmanaged_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
9973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tnative_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n",
9983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         managed_code_bytes, PercentOfOatBytes(managed_code_bytes),
9993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         managed_to_native_code_bytes, PercentOfOatBytes(managed_to_native_code_bytes),
10003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         native_to_managed_code_bytes, PercentOfOatBytes(native_to_managed_code_bytes))
10013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << std::endl << std::flush;
10023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
10033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\tgc_map_bytes           = %7zd (%2.0f%% of oat file_bytes)\n"
10043a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tpc_mapping_table_bytes = %7zd (%2.0f%% of oat file_bytes)\n"
10053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tvmap_table_bytes       = %7zd (%2.0f%% of oat file_bytes)\n",
10063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         gc_map_bytes, PercentOfOatBytes(gc_map_bytes),
10073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         pc_mapping_table_bytes, PercentOfOatBytes(pc_mapping_table_bytes),
10083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
10093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << std::endl << std::flush;
1010916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
1011ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes      os << StringPrintf("\tdex_instruction_bytes = %zd\n", dex_instruction_bytes);
10123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\tmanaged_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n",
10133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          static_cast<double>(managed_code_bytes) / static_cast<double>(dex_instruction_bytes),
10143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
10153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            static_cast<double>(dex_instruction_bytes));
10163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
10173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
10183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOutliers(os);
1019916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    }
1020916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom  } stats_;
1021916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
1022916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom private:
10233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  UniquePtr<OatDumper> oat_dumper_;
102427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  std::ostream& os_;
10253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const std::string image_filename_;
10263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const std::string host_prefix_;
10273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  Space& image_space_;
10283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const ImageHeader& image_header_;
1029d1bb4f6b7c8dda429f61937cd42f3a0b7367c271Elliott Hughes
10303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  DISALLOW_COPY_AND_ASSIGN(ImageDumper);
103178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom};
103278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
103378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstromint oatdump(int argc, char** argv) {
103478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  // Skip over argv[0].
103578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  argv++;
103678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  argc--;
103778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
103878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  if (argc == 0) {
1039aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    fprintf(stderr, "No arguments specified\n");
104078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    usage();
104178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
104278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1043aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  const char* oat_filename = NULL;
104478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  const char* image_filename = NULL;
104578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  const char* boot_image_filename = NULL;
104658ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  std::string host_prefix;
104727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  std::ostream* os = &std::cout;
104827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  UniquePtr<std::ofstream> out;
104978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
105078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  for (int i = 0; i < argc; i++) {
105178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    const StringPiece option(argv[i]);
1052a6cc893c4b142cd410fc956963b6f5a014e983adBrian Carlstrom    if (option.starts_with("--oat-file=")) {
1053a6cc893c4b142cd410fc956963b6f5a014e983adBrian Carlstrom      oat_filename = option.substr(strlen("--oat-file=")).data();
1054aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    } else if (option.starts_with("--image=")) {
105578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      image_filename = option.substr(strlen("--image=")).data();
1056e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom    } else if (option.starts_with("--boot-image=")) {
1057e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom      boot_image_filename = option.substr(strlen("--boot-image=")).data();
105858ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    } else if (option.starts_with("--host-prefix=")) {
105958ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom      host_prefix = option.substr(strlen("--host-prefix=")).data();
106027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    } else if (option.starts_with("--output=")) {
106127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      const char* filename = option.substr(strlen("--output=")).data();
106227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      out.reset(new std::ofstream(filename));
106327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      if (!out->good()) {
1064aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom        fprintf(stderr, "Failed to open output filename %s\n", filename);
106527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom        usage();
106627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      }
106727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      os = out.get();
106878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    } else {
1069aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      fprintf(stderr, "Unknown argument %s\n", option.data());
107078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      usage();
107178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
107278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
107378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1074aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (image_filename == NULL && oat_filename == NULL) {
1075362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    fprintf(stderr, "Either --image or --oat must be specified\n");
1076362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    return EXIT_FAILURE;
107778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
107878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1079aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (image_filename != NULL && oat_filename != NULL) {
1080362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    fprintf(stderr, "Either --image or --oat must be specified but not both\n");
1081362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    return EXIT_FAILURE;
1082aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
1083aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
1084aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (oat_filename != NULL) {
10853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, NULL);
1086aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    if (oat_file == NULL) {
1087aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
1088aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      return EXIT_FAILURE;
1089aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
10903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    OatDumper oat_dumper(*oat_file);
10913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    oat_dumper.Dump(*os);
1092aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    return EXIT_SUCCESS;
1093aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
1094aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
109578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  Runtime::Options options;
109678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  std::string image_option;
1097e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  std::string oat_option;
109878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  std::string boot_image_option;
1099e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  std::string boot_oat_option;
110058ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  if (boot_image_filename != NULL) {
110158ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    boot_image_option += "-Ximage:";
110258ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    boot_image_option += boot_image_filename;
110358ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
110458ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  }
1105aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (image_filename != NULL) {
1106aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    image_option += "-Ximage:";
1107aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    image_option += image_filename;
1108aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
1109aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
111058ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom
1111fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom  if (host_prefix.empty()) {
1112fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom    const char* android_product_out = getenv("ANDROID_PRODUCT_OUT");
1113fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom    if (android_product_out != NULL) {
1114fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom        host_prefix = android_product_out;
1115fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom    }
1116fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom  }
111758ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  if (!host_prefix.empty()) {
111858ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    options.push_back(std::make_pair("host-prefix", host_prefix.c_str()));
111978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
112078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
112178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  UniquePtr<Runtime> runtime(Runtime::Create(options, false));
112278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  if (runtime.get() == NULL) {
1123aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    fprintf(stderr, "Failed to create runtime\n");
112478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    return EXIT_FAILURE;
112578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
112678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
112730fab40ee5a07af6b8c3b6b0e9438071695a57f4Ian Rogers  ImageSpace* image_space = Heap::GetSpaces()[Heap::GetSpaces().size()-2]->AsImageSpace();
112878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  CHECK(image_space != NULL);
112978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  const ImageHeader& image_header = image_space->GetImageHeader();
113078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  if (!image_header.IsValid()) {
1131aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    fprintf(stderr, "Invalid image header %s\n", image_filename);
113278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    return EXIT_FAILURE;
113378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
11343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  ImageDumper image_dumper(*os, image_filename, host_prefix, *image_space, image_header);
11353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  image_dumper.Dump();
113678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  return EXIT_SUCCESS;
113778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom}
113878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
113978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom} // namespace art
114078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
114178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstromint main(int argc, char** argv) {
114278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  return art::oatdump(argc, argv);
114378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom}
1144