oatdump.cc revision f8bbb8448c733e9e3ad43aad69774c37888329b1
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
141f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  InstructionSet GetInstructionSet() {
142f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    return oat_file_.GetOatHeader().GetInstructionSet();
143f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  }
144f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom
1453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const void* GetOatCode(Method* m) {
1463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    MethodHelper mh(m);
1473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < oat_dex_files_.size(); i++) {
1483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
149aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      CHECK(oat_dex_file != NULL);
1503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
1513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (dex_file.get() != NULL) {
1523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        uint32_t class_def_index;
1533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool found = dex_file->FindClassDefIndex(mh.GetDeclaringClassDescriptor(), class_def_index);
1543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (found) {
1553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index);
1563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          CHECK(oat_class != NULL);
1573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          size_t method_index = m->GetMethodIndex();
1583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          return oat_class->GetOatMethod(method_index).GetCode();
1593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
1603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
161aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
1623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return NULL;
163aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
164aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
165aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom private:
1663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void AddAllOffsets() {
167e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // We don't know the length of the code for each method, but we need to know where to stop
168e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // when disassembling. What we do know is that a region of code will be followed by some other
169e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // region, so if we keep a sorted sequence of the start of each region, we can infer the length
170e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // of a piece of code by using upper_bound to find the start of the next region.
1713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < oat_dex_files_.size(); i++) {
1723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
173e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      CHECK(oat_dex_file != NULL);
174e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
175e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      if (dex_file.get() == NULL) {
1763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        continue;
177e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      }
1783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      offsets_.insert(reinterpret_cast<uint32_t>(&dex_file->GetHeader()));
179e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
180e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
181e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
182e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        const byte* class_data = dex_file->GetClassData(class_def);
183e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        if (class_data != NULL) {
184e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          ClassDataItemIterator it(*dex_file, class_data);
185e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          SkipAllFields(it);
186e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          uint32_t class_method_index = 0;
187e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          while (it.HasNextDirectMethod()) {
188e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            AddOffsets(oat_class->GetOatMethod(class_method_index++));
189e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            it.Next();
190e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          }
191e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          while (it.HasNextVirtualMethod()) {
192e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            AddOffsets(oat_class->GetOatMethod(class_method_index++));
193e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes            it.Next();
194e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes          }
195e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        }
196e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      }
197e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
198e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
199e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // If the last thing in the file is code for a method, there won't be an offset for the "next"
200e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // thing. Instead of having a special case in the upper_bound code, let's just add an entry
201e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    // for the end of the file.
2023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    offsets_.insert(static_cast<uint32_t>(oat_file_.End() - oat_file_.Begin()));
203e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
204e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
205e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  void AddOffsets(const OatFile::OatMethod& oat_method) {
20695ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    uint32_t code_offset = oat_method.GetCodeOffset();
20795ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
20895ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom      code_offset &= ~0x1;
20995ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    }
21095ba0dc516531776813c426e85ce868ead564a7bBrian Carlstrom    offsets_.insert(code_offset);
211e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetMappingTableOffset());
212e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetVmapTableOffset());
213e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetGcMapOffset());
214e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    offsets_.insert(oat_method.GetInvokeStubOffset());
215e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
216e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
2173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
218aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << "OAT DEX FILE:\n";
219a004aa933a58428489e42d77f707c2b063b73747Brian Carlstrom    os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
220ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
221a004aa933a58428489e42d77f707c2b063b73747Brian Carlstrom    UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile());
222a004aa933a58428489e42d77f707c2b063b73747Brian Carlstrom    if (dex_file.get() == NULL) {
223aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      os << "NOT FOUND\n\n";
224aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      return;
225aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
226aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
227aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
228aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      const char* descriptor = dex_file->GetClassDescriptor(class_def);
229aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
230aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      CHECK(oat_class.get() != NULL);
231ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes      os << StringPrintf("%zd: %s (type_idx=%d) (", class_def_index, descriptor, class_def.class_idx_)
232e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom         << oat_class->GetStatus() << ")\n";
2333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatClass(os, *oat_class.get(), *(dex_file.get()), class_def);
234aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
235aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
236aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << std::flush;
237aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
238aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
239e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  static void SkipAllFields(ClassDataItemIterator& it) {
2400571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextStaticField()) {
2410571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
242aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
2430571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextInstanceField()) {
2440571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
245aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
246e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
247aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
2483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
2493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    const DexFile::ClassDef& class_def) {
250e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const byte* class_data = dex_file.GetClassData(class_def);
251e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    if (class_data == NULL) {  // empty class such as a marker interface?
252e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      return;
253e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
254e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    ClassDataItemIterator it(dex_file, class_data);
255e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    SkipAllFields(it);
256e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
257e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    uint32_t class_method_index = 0;
2580571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextDirectMethod()) {
259e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
2603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatMethod(os, class_method_index, oat_method, dex_file,
2613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    it.GetMemberIndex(), it.GetMethodCodeItem());
262e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      class_method_index++;
2630571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
264aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
2650571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    while (it.HasNextVirtualMethod()) {
266e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
2673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOatMethod(os, class_method_index, oat_method, dex_file,
2683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    it.GetMemberIndex(), it.GetMethodCodeItem());
269e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      class_method_index++;
2700571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers      it.Next();
271aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
2720571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers    DCHECK(!it.HasNext());
273aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    os << std::flush;
274aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
275e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
2763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpOatMethod(std::ostream& os, uint32_t class_method_index,
277e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes                     const OatFile::OatMethod& oat_method, const DexFile& dex_file,
278e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes                     uint32_t dex_method_idx, const DexFile::CodeItem* code_item) {
279e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
280aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    const char* name = dex_file.GetMethodName(method_id);
281955724179c6c739524f610023287f56b24dc31deElliott Hughes    std::string signature(dex_file.GetMethodSignature(method_id));
282e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    os << StringPrintf("\t%d: %s %s (dex_method_idx=%d)\n",
283e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes                       class_method_index, name, signature.c_str(), dex_method_idx);
284ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tcode: %p (offset=0x%08x)\n",
285ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetCode(), oat_method.GetCodeOffset());
286ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes    os << StringPrintf("\t\tframe_size_in_bytes: %zd\n",
287ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetFrameSizeInBytes());
2883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << StringPrintf("\t\tcore_spill_mask: 0x%08x",
289ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetCoreSpillMask());
2903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpSpillMask(os, oat_method.GetCoreSpillMask(), false);
2913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << StringPrintf("\n\t\tfp_spill_mask: 0x%08x",
292ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetFpSpillMask());
2933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpSpillMask(os, oat_method.GetFpSpillMask(), true);
2943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << StringPrintf("\n\t\tmapping_table: %p (offset=0x%08x)\n",
295ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
2963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpMappingTable(os, oat_method);
297ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tvmap_table: %p (offset=0x%08x)\n",
298ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
2993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpVmap(os, oat_method.GetVmapTable(), oat_method.GetCoreSpillMask(),
3003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers             oat_method.GetFpSpillMask());
301ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tgc_map: %p (offset=0x%08x)\n",
302e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom                       oat_method.GetGcMap(), oat_method.GetGcMapOffset());
3033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpGcMap(os, oat_method.GetGcMap());
304ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes    os << StringPrintf("\t\tinvoke_stub: %p (offset=0x%08x)\n",
305ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom                       oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
306f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    os << "\t\tCODE: (size=" << oat_method.GetCodeSize() << ")\n";
3073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpCode(os, oat_method.GetCode(), oat_method.GetMappingTable(), dex_file, code_item);
308f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    os << "\t\tINVOKE STUB: (size=" << oat_method.GetInvokeStubSize() << ")\n";
3093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DumpCode(os, reinterpret_cast<const void*>(oat_method.GetInvokeStub()), NULL, dex_file, NULL);
3103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
3113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
3123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
3133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (spill_mask == 0) {
3143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
3153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << " (";
3173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < 32; i++) {
3183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if ((spill_mask & (1 << i)) != 0) {
3193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (is_float) {
3203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          os << "fr" << i;
3213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        } else {
3223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          os << "r" << i;
3233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        spill_mask ^= 1 << i;  // clear bit
3253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (spill_mask != 0) {
3263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          os << ", ";
3273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        } else {
3283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
3293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << ")";
3333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
3343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
3353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpVmap(std::ostream& os, const uint16_t* raw_table, uint32_t core_spill_mask,
3363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                uint32_t fp_spill_mask) {
3373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (raw_table == NULL) {
3383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
3393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    const VmapTable vmap_table(raw_table);
3413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    bool first = true;
3423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "\t\t\t";
3433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < vmap_table.size(); i++) {
3443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint16_t dex_reg = vmap_table[i];
3453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t matches = 0;
3463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t spill_shifts = 0;
3473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint32_t spill_mask = core_spill_mask;
3483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      bool processing_fp = false;
3493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      while (matches != (i + 1)) {
3503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (spill_mask == 0) {
3513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          CHECK(!processing_fp);
3523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          spill_mask = fp_spill_mask;
3533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          processing_fp = true;
3543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        matches += spill_mask & 1;  // Add 1 if the low bit is set
3563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        spill_mask >>= 1;
3573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        spill_shifts++;
3583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t arm_reg = spill_shifts - 1;  // wind back one as we want the last match
3603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << (first ? "v" : ", v")  << dex_reg;
3613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (arm_reg < 16) {
3623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "/r" << arm_reg;
3633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      } else {
3643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "/fr" << (arm_reg - 16);
3653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (first) {
3673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        first = false;
3683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << std::endl;
3713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
3723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
3733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpGcMap(std::ostream& os, const uint8_t* gc_map_raw) {
3743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (gc_map_raw == NULL) {
3753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
3763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
3773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint32_t gc_map_length = (gc_map_raw[0] << 24) | (gc_map_raw[1] << 16) |
3783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                             (gc_map_raw[2] << 8) | (gc_map_raw[3] << 0);
3793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    verifier::PcToReferenceMap map(gc_map_raw + sizeof(uint32_t), gc_map_length);
3803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t entry = 0; entry < map.NumEntries(); entry++) {
3813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\t\t\t0x%04x", map.GetPC(entry));
3823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t num_regs = map.RegWidth() * 8;
3833a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* reg_bitmap = map.GetBitMap(entry);
3843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      bool first = true;
3853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t reg = 0; reg < num_regs; reg++) {
3863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
3873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (first) {
3883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os << "  v" << reg;
3893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            first = false;
3903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          } else {
3913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os << ", v" << reg;
3923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
3933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
3943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
3953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl;
3963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
397aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
398e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
3993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
400e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const uint32_t* raw_table = oat_method.GetMappingTable();
401e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    const void* code = oat_method.GetCode();
402e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    if (raw_table == NULL || code == NULL) {
403e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      return;
404e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
405e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
406e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    uint32_t length = *raw_table;
407e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    ++raw_table;
408e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
4093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "\t\t{";
410e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    for (size_t i = 0; i < length; i += 2) {
4113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) + raw_table[i];
412e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      uint32_t dex_pc = raw_table[i + 1];
4133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("%p -> 0x%04x", native_pc, dex_pc);
4143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (i + 2 < length) {
4153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << ", ";
4163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
4173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
4183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "}" << std::endl << std::flush;
4193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
4203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void DumpCode(std::ostream& os, const void* code, const uint32_t* raw_mapping_table,
4223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                const DexFile& dex_file, const DexFile::CodeItem* code_item) {
4233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (code == NULL) {
4243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
4253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
4263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (raw_mapping_table == NULL) {
4283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // code but no mapping table is most likely caused by code created by the JNI compiler
4293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code);
4303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* oat_begin = reinterpret_cast<const uint8_t*>(oat_file_.Begin());
4313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint32_t last_offset = static_cast<uint32_t>(native_pc - oat_begin);
4323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      typedef std::set<uint32_t>::iterator It;
4343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      It it = offsets_.upper_bound(last_offset);
4353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      CHECK(it != offsets_.end());
4363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* end_native_pc = reinterpret_cast<const uint8_t*>(oat_begin) + *it;
4373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      CHECK(native_pc < end_native_pc);
4383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      disassembler_->Dump(os, native_pc, end_native_pc);
4403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return;
4413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
4423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint32_t length = *raw_mapping_table;
4443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    ++raw_mapping_table;
4453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
4463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (size_t i = 0; i < length; i += 2) {
4473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint32_t dex_pc = raw_mapping_table[i + 1];
448e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const Instruction* instruction = Instruction::At(&code_item->insns_[dex_pc]);
449e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      os << StringPrintf("\t\t0x%04x: %s\n", dex_pc, instruction->DumpString(&dex_file).c_str());
450e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
4513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) + raw_mapping_table[i];
452e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      const uint8_t* end_native_pc = NULL;
453e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      if (i + 2 < length) {
4543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        end_native_pc = reinterpret_cast<const uint8_t*>(code) + raw_mapping_table[i + 2];
455e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      } else {
4563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        const uint8_t* oat_begin = reinterpret_cast<const uint8_t*>(oat_file_.Begin());
457e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        uint32_t last_offset = static_cast<uint32_t>(native_pc - oat_begin);
458e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
459e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        typedef std::set<uint32_t>::iterator It;
460ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes        It it = offsets_.upper_bound(last_offset);
461e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        CHECK(it != offsets_.end());
462e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes        end_native_pc = reinterpret_cast<const uint8_t*>(oat_begin) + *it;
463e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes      }
464ed2adb6158ffbe85c89aa5c9892a35bafa5006cdElliott Hughes      CHECK(native_pc < end_native_pc);
4653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      disassembler_->Dump(os, native_pc, end_native_pc);
466e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes    }
467e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  }
468e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes
4693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const OatFile& oat_file_;
4703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  std::vector<const OatFile::OatDexFile*> oat_dex_files_;
471e3c845cdb5884e770287a5c0c65c8bb64733c388Elliott Hughes  std::set<uint32_t> offsets_;
4723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  UniquePtr<Disassembler> disassembler_;
473aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom};
474aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
4753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogersclass ImageDumper {
47627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom public:
4773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  explicit ImageDumper(std::ostream& os, const std::string& image_filename,
4783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       const std::string& host_prefix, Space& image_space,
4793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       const ImageHeader& image_header) : os_(os),
4803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       image_filename_(image_filename), host_prefix_(host_prefix),
4813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                       image_space_(image_space), image_header_(image_header) {
4823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
48327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
4843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  void Dump() {
4853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "MAGIC:\n";
4863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << image_header_.GetMagic() << "\n\n";
487e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom
4883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "IMAGE BEGIN:\n";
4893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
490aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
4913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT CHECKSUM:\n";
4923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
493916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
4943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT BEGIN:\n";
4953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetOatBegin()) << "\n\n";
496aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
4973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OAT END:\n";
4983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetOatEnd()) << "\n\n";
4993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "ROOTS:\n";
5013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
502418d20fc407052d4152157f61e7453359f902383Elliott Hughes    CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
50327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
50427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
50534f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom      const char* image_root_description = image_roots_descriptions_[i];
5063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      Object* image_root_object = image_header_.GetImageRoot(image_root);
5073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os_ << StringPrintf("%s: %p\n", image_root_description, image_root_object);
50834f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom      if (image_root_object->IsObjectArray()) {
50934f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        // TODO: replace down_cast with AsObjectArray (g++ currently has a problem with this)
51034f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        ObjectArray<Object>* image_root_object_array
51134f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom            = down_cast<ObjectArray<Object>*>(image_root_object);
51234f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        //  = image_root_object->AsObjectArray<Object>();
51334f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        for (int i = 0; i < image_root_object_array->GetLength(); i++) {
514d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          Object* value = image_root_object_array->Get(i);
515d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          if (value != NULL) {
5163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os_ << "\t" << i << ": ";
517d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            std::string summary;
518d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            PrettyObjectValue(summary, value->GetClass(), value);
5193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os_ << summary;
520d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          } else {
5213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            os_ << StringPrintf("\t%d: null\n", i);
522d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          }
52334f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom        }
52434f426c49ac2de8cea70acef6b9ecdd8e62209d2Brian Carlstrom      }
52527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    }
5263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
52727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
5284dcbffb3c6e8757d127dede32c8efa6c04e44a70Brian Carlstrom    os_ << "OAT LOCATION:\n" << std::flush;
529aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
5303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    Object* oat_location_object = image_header_.GetImageRoot(ImageHeader::kOatLocation);
5313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::string oat_location(oat_location_object->AsString()->ToModifiedUtf8());
5324dcbffb3c6e8757d127dede32c8efa6c04e44a70Brian Carlstrom    os_ << oat_location;
5333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (!host_prefix_.empty()) {
5343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      oat_location = host_prefix_ + oat_location;
5353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os_ << " (" << oat_location << ")";
536aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
5374dcbffb3c6e8757d127dede32c8efa6c04e44a70Brian Carlstrom    os_ << "\n";
538ae826983f7903bc0a6bbbe8426bf393fb2f6d747Brian Carlstrom    const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location);
539aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    if (oat_file == NULL) {
5404dcbffb3c6e8757d127dede32c8efa6c04e44a70Brian Carlstrom      os_ << "NOT FOUND\n";
541aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      return;
542aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
5434dcbffb3c6e8757d127dede32c8efa6c04e44a70Brian Carlstrom    os_ << "\n";
544aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
5453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.oat_file_bytes = oat_file->Size();
54678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
5473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    oat_dumper_.reset(new OatDumper(*oat_file));
5483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "OBJECTS:\n" << std::flush;
550b3bd5f07884f5a1f2b84224363b1372d7c28d447Elliott Hughes    HeapBitmap* heap_bitmap = Runtime::Current()->GetHeap()->GetLiveBits();
5513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    DCHECK(heap_bitmap != NULL);
5523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    heap_bitmap->Walk(ImageDumper::Callback, this);
5533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
5543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "STATS:\n" << std::flush;
5563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    UniquePtr<File> file(OS::OpenFile(image_filename_.c_str(), false));
5573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.file_bytes = file->Length();
5583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t header_bytes = sizeof(ImageHeader);
5593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.header_bytes = header_bytes;
5603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
5613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.alignment_bytes += alignment_bytes;
5623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    stats_.Dump(os_);
5633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << "\n";
56427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
5653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os_ << std::flush;
5663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    oat_dumper_->Dump(os_);
5683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
569d1bb4f6b7c8dda429f61937cd42f3a0b7367c271Elliott Hughes
5703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers private:
57127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
572d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  static void PrettyObjectValue(std::string& summary, Class* type, Object* value) {
573d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    CHECK(type != NULL);
574d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (value == NULL) {
575d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "null   %s\n", PrettyDescriptor(type).c_str());
576d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsStringClass()) {
577d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      String* string = value->AsString();
578d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   String: \"%s\"\n", string, string->ToModifiedUtf8().c_str());
579d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (value->IsClass()) {
580d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Class* klass = value->AsClass();
581d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
582d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (value->IsField()) {
583d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Field* field = value->AsField();
584d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   Field: %s\n", field, PrettyField(field).c_str());
585d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (value->IsMethod()) {
586d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Method* method = value->AsMethod();
587d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   Method: %s\n", method, PrettyMethod(method).c_str());
588d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else {
589d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p   %s\n", value, PrettyDescriptor(type).c_str());
590d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
591d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  }
592d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
593d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  static void PrintField(std::string& summary, Field* field, Object* obj) {
594d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    FieldHelper fh(field);
595d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    Class* type = fh.GetType();
596d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    StringAppendF(&summary, "\t%s: ", fh.GetName());
597d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (type->IsPrimitiveLong()) {
598d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%lld (0x%llx)\n", field->Get64(obj), field->Get64(obj));
599d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsPrimitiveDouble()) {
600d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
601d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsPrimitiveFloat()) {
602d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
603d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (type->IsPrimitive()){
604d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
605d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else {
606d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Object* value = field->GetObj(obj);
607d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      PrettyObjectValue(summary, type, value);
608d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
609d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  }
610d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
611d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  static void DumpFields(std::string& summary, Object* obj, Class* klass) {
612d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    Class* super = klass->GetSuperClass();
613d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (super != NULL) {
614d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      DumpFields(summary, obj, super);
615d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
616d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    ObjectArray<Field>* fields = klass->GetIFields();
617d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (fields != NULL) {
618d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      for (int32_t i = 0; i < fields->GetLength(); i++) {
619d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        Field* field = fields->Get(i);
620d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        PrintField(summary, field, obj);
621d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      }
622d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    }
623d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers  }
624d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
6253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  bool InDumpSpace(const Object* object) {
6263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return image_space_.Contains(object);
627f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  }
6283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
629f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  const void* GetOatCodeBegin(Method* m) {
6303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    Runtime* runtime = Runtime::Current();
6313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    const void* code = m->GetCode();
632fb6adba0d5d5505610fbd325e7911db700a2f1e8Ian Rogers    if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
6333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      code = oat_dumper_->GetOatCode(m);
6343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
635f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    if (oat_dumper_->GetInstructionSet() == kThumb2) {
636f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom      code = reinterpret_cast<void*>(reinterpret_cast<uint32_t>(code) & ~0x1);
637f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    }
6383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return code;
6393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
6403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
641f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  uint32_t GetOatCodeSize(Method* m) {
642f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetOatCodeBegin(m));
643f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    if (oat_code_begin == NULL) {
644f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom      return 0;
645f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    }
646f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    return oat_code_begin[-1];
647f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  }
648f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom
649f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  const void* GetOatCodeEnd(Method* m) {
650f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetOatCodeBegin(m));
651f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    if (oat_code_begin == NULL) {
652f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom      return NULL;
653f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    }
654f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom    return oat_code_begin + GetOatCodeSize(m);
655f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom  }
656f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom
65778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  static void Callback(Object* obj, void* arg) {
65878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    DCHECK(obj != NULL);
65978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    DCHECK(arg != NULL);
6603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
66178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    if (!state->InDumpSpace(obj)) {
66278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      return;
66378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
664916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
665916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t object_bytes = obj->SizeOf();
666916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
667916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    state->stats_.object_bytes += object_bytes;
668916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    state->stats_.alignment_bytes += alignment_bytes;
669916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
67078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    std::string summary;
671d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    Class* obj_class = obj->GetClass();
672d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (obj_class->IsArrayClass()) {
673d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
674d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    obj->AsArray()->GetLength());
675d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsClass()) {
67678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      Class* klass = obj->AsClass();
677d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.Class \"%s\" (", obj,
678d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    PrettyDescriptor(klass).c_str());
6793b6baaa203fa63f1522b2172a1645f90412afdaeElliott Hughes      std::ostringstream ss;
680d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      ss << klass->GetStatus() << ")\n";
681e10b6974d54f38001aee7bec518d45a7d4fb64c1Brian Carlstrom      summary += ss.str();
68278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    } else if (obj->IsField()) {
683d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.reflect.Field %s\n", obj,
684d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    PrettyField(obj->AsField()).c_str());
685d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsMethod()) {
686d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.reflect.Method %s\n", obj,
687d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    PrettyMethod(obj->AsMethod()).c_str());
688d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj_class->IsStringClass()) {
689d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: java.lang.String \"%s\"\n", obj,
690d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers                    obj->AsString()->ToModifiedUtf8().c_str());
69178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    } else {
692d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      StringAppendF(&summary, "%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
69378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
694d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    DumpFields(summary, obj, obj_class);
695d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    if (obj->IsObjectArray()) {
696d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      ObjectArray<Object>* obj_array = obj->AsObjectArray<Object>();
697d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      int32_t length = obj_array->GetLength();
698d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      for (int32_t i = 0; i < length; i++) {
699d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        Object* value = obj_array->Get(i);
700d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        size_t run = 0;
701d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        for (int32_t j = i + 1; j < length; j++) {
702d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          if (value == obj_array->Get(j)) {
703d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            run++;
704d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          } else {
705d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers            break;
706d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          }
707d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        }
708d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        if (run == 0) {
709d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          StringAppendF(&summary, "\t%d: ", i);
71078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom        } else {
711c1051ae94c5bd45367152a603f3946a933ad91faElliott Hughes          StringAppendF(&summary, "\t%d to %zd: ", i, i + run);
712d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          i = i + run;
71378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom        }
714d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        Class* value_class = value == NULL ? obj_class->GetComponentType() : value->GetClass();
715d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        PrettyObjectValue(summary, value_class, value);
716d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      }
717d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsClass()) {
718d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      ObjectArray<Field>* sfields = obj->AsClass()->GetSFields();
719d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      if (sfields != NULL) {
720d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        summary += "\t\tSTATICS:\n";
721d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        for (int32_t i = 0; i < sfields->GetLength(); i++) {
722d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          Field* field = sfields->Get(i);
723d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers          PrintField(summary, field, NULL);
724d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        }
725d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      }
726d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    } else if (obj->IsMethod()) {
727d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      Method* method = obj->AsMethod();
728d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers      if (method->IsNative()) {
729d81871cbbaa34c649e488f94f61a981db33123e5Ian Rogers        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
730e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
7313320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
7323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first_occurrence;
7333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t invoke_stub_size = state->ComputeOatSize(
7343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            reinterpret_cast<const void*>(method->GetInvokeStub()), &first_occurrence);
7353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurrence) {
7363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.managed_to_native_code_bytes += invoke_stub_size;
7373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
738f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        const void* oat_code = state->GetOatCodeBegin(method);
7393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t code_size = state->ComputeOatSize(oat_code, &first_occurrence);
7403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurrence) {
7413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.native_to_managed_code_bytes += code_size;
7423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (oat_code != method->GetCode()) {
7443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          StringAppendF(&summary, "\t\tOAT CODE: %p\n", oat_code);
7453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7461984651929744dd603fd082e23eacd877b9bc177Ian Rogers      } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
7471984651929744dd603fd082e23eacd877b9bc177Ian Rogers          method->IsResolutionMethod()) {
748d81871cbbaa34c649e488f94f61a981db33123e5Ian Rogers        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
749e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
7503320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
751916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      } else {
752e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK(method->GetGcMap() != NULL) << PrettyMethod(method);
753e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom        DCHECK_NE(0U, method->GetGcMapLength()) << PrettyMethod(method);
754916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
7556d4d9fcb4f01e287ee29e81cd1c941ee5d11d379Ian Rogers        const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
756d81871cbbaa34c649e488f94f61a981db33123e5Ian Rogers        size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
757916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        state->stats_.dex_instruction_bytes += dex_instruction_bytes;
758e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom
7593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first_occurance;
7603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t gc_map_bytes = state->ComputeOatSize(method->GetGcMapRaw(), &first_occurance);
7613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.gc_map_bytes += gc_map_bytes;
7633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t pc_mapping_table_bytes =
7663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            state->ComputeOatSize(method->GetMappingTableRaw(), &first_occurance);
7673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
7693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t vmap_table_bytes =
7723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            state->ComputeOatSize(method->GetVmapTableRaw(), &first_occurance);
7733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.vmap_table_bytes += vmap_table_bytes;
7753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t invoke_stub_size = state->ComputeOatSize(
7783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            reinterpret_cast<const void*>(method->GetInvokeStub()), &first_occurance);
7793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.native_to_managed_code_bytes += invoke_stub_size;
7813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
782f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        const void* oat_code_begin = state->GetOatCodeBegin(method);
783f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        const void* oat_code_end = state->GetOatCodeEnd(method);
784f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        // TODO: use oat_code_size and remove code_size based on offsets
785f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        // uint32_t oat_code_size = state->GetOatCodeSize(method);
786f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        size_t code_size = state->ComputeOatSize(oat_code_begin, &first_occurance);
7873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        if (first_occurance) {
7883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          state->stats_.managed_code_bytes += code_size;
7893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
7903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        state->stats_.managed_code_bytes_ignoring_deduplication += code_size;
7913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
792f8bbb8448c733e9e3ad43aad69774c37888329b1Brian Carlstrom        StringAppendF(&summary, "\t\tOAT CODE: %p-%p\n", oat_code_begin, oat_code_end);
793d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers        StringAppendF(&summary, "\t\tSIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
7943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                      dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
7953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
7973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            vmap_table_bytes + invoke_stub_size + code_size + object_bytes;
7983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
7993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        double expansion =
8003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            static_cast<double>(code_size) / static_cast<double>(dex_instruction_bytes);
8013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        state->stats_.ComputeOutliers(total_size, expansion, method);
80278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      }
80378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
804d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    std::string descriptor(ClassHelper(obj_class).GetDescriptor());
805d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    state->stats_.descriptor_to_bytes[descriptor] += object_bytes;
806d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers    state->stats_.descriptor_to_count[descriptor] += 1;
807d5b32607798a46a905ba2d8d5bf7507cc970aa58Ian Rogers
80827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    state->os_ << summary << std::flush;
80978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
81027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom
8113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  std::set<const void*> already_seen_;
8123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // Compute the size of the given data within the oat file and whether this is the first time
8133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // this data has been requested
8143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  size_t ComputeOatSize(const void* oat_data, bool* first_occurance) {
8153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (already_seen_.count(oat_data) == 0) {
8163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      *first_occurance = true;
8173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      already_seen_.insert(oat_data);
8183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    } else {
8193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      *first_occurance = false;
8203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
8213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return oat_dumper_->ComputeSize(oat_data);
82227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  }
823916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
824916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom public:
825916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom  struct Stats {
8263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t oat_file_bytes;
827916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t file_bytes;
828916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
829916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t header_bytes;
830916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t object_bytes;
831916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t alignment_bytes;
832916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
833916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t managed_code_bytes;
8343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t managed_code_bytes_ignoring_deduplication;
835916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t managed_to_native_code_bytes;
836916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t native_to_managed_code_bytes;
837916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t gc_map_bytes;
839916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t pc_mapping_table_bytes;
8403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    size_t vmap_table_bytes;
841916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
842916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    size_t dex_instruction_bytes;
843916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::vector<Method*> method_outlier;
8453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::vector<size_t> method_outlier_size;
8463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    std::vector<double> method_outlier_expansion;
8473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
8483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    explicit Stats()
8493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        : oat_file_bytes(0),
8503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          file_bytes(0),
851916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          header_bytes(0),
852916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          object_bytes(0),
853916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          alignment_bytes(0),
854916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          managed_code_bytes(0),
8553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          managed_code_bytes_ignoring_deduplication(0),
856916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          managed_to_native_code_bytes(0),
857916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          native_to_managed_code_bytes(0),
8583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          gc_map_bytes(0),
859916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          pc_mapping_table_bytes(0),
8603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          vmap_table_bytes(0),
861916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom          dex_instruction_bytes(0) {}
862916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
863e5448b5a12003b405b22cde3b94f962ab4888a87Elliott Hughes    typedef std::map<std::string, size_t> TableBytes;
864916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    TableBytes descriptor_to_bytes;
865916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
866e5448b5a12003b405b22cde3b94f962ab4888a87Elliott Hughes    typedef std::map<std::string, size_t> TableCount;
867916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    TableCount descriptor_to_count;
868916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    double PercentOfOatBytes(size_t size) {
8703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
8713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
8723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
873916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    double PercentOfFileBytes(size_t size) {
874916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
875916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    }
876916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
877916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    double PercentOfObjectBytes(size_t size) {
878916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
879916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    }
880916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
8813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    void ComputeOutliers(size_t total_size, double expansion, Method* method) {
8823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      method_outlier_size.push_back(total_size);
8833a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      method_outlier_expansion.push_back(expansion);
8843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      method_outlier.push_back(method);
8853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
8863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
8873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    void DumpOutliers(std::ostream& os) {
8883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_sizes = 0;
8893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_sizes_squared = 0;
8903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_expansion = 0;
8913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t sum_of_expansion_squared = 0;
8923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t n = method_outlier_size.size();
8933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t i = 0; i < n; i++) {
8943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t cur_size = method_outlier_size[i];
8953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_sizes += cur_size;
8963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_sizes_squared += cur_size * cur_size;
8973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        double cur_expansion = method_outlier_expansion[i];
8983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_expansion += cur_expansion;
8993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        sum_of_expansion_squared += cur_expansion * cur_expansion;
9003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t size_mean = sum_of_sizes / n;
9023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
9033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      double expansion_mean = sum_of_expansion / n;
9043a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      double expansion_variance =
9053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
9063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
9073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Dump methods whose size is a certain number of standard deviations from the mean
9083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t dumped_values = 0;
9093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      size_t skipped_values = 0;
9103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
9113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        size_t cur_size_variance = i * i * size_variance;
9123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first = true;
9133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        for (size_t j = 0; j < n; j++) {
9143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          size_t cur_size = method_outlier_size[j];
9153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (cur_size > size_mean) {
9163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            size_t cur_var = cur_size - size_mean;
9173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            cur_var = cur_var * cur_var;
9183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            if (cur_var > cur_size_variance) {
9193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              if (dumped_values > 20) {
9203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (i == 1) {
9213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  skipped_values++;
9223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                } else {
9233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  i = 2;  // jump to counting for 1 standard deviation
9243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  break;
9253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              } else {
9273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (first) {
9283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  os << "\nBig methods (size > " << i << " standard deviations the norm):"
9293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                     << std::endl;
9303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  first = false;
9313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                os << "\t" << PrettyMethod(method_outlier[j]) << " requires storage of "
9333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    << PrettySize(cur_size) << std::endl;
9343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                method_outlier_size[j] = 0;  // don't consider this method again
9353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                dumped_values++;
9363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              }
9373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            }
9383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
9393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
9403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (skipped_values > 0) {
9423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "\t... skipped " << skipped_values
9433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers           << " methods with size > 1 standard deviation from the norm" << std::endl;
9443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
9463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
9473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Dump methods whose expansion is a certain number of standard deviations from the mean
9483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      dumped_values = 0;
9493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      skipped_values = 0;
9503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
9513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        double cur_expansion_variance = i * i * expansion_variance;
9523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        bool first = true;
9533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        for (size_t j = 0; j < n; j++) {
9543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          double cur_expansion = method_outlier_expansion[j];
9553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (cur_expansion > expansion_mean) {
9563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            size_t cur_var = cur_expansion - expansion_mean;
9573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            cur_var = cur_var * cur_var;
9583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            if (cur_var > cur_expansion_variance) {
9593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              if (dumped_values > 20) {
9603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (i == 1) {
9613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  skipped_values++;
9623a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                } else {
9633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  i = 2;  // jump to counting for 1 standard deviation
9643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  break;
9653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              } else {
9673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                if (first) {
9683a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  os << "\nLarge expansion methods (size > " << i
9693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                      << " standard deviations the norm):" << std::endl;
9703a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                  first = false;
9713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                }
9723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                os << "\t" << PrettyMethod(method_outlier[j]) << " expanded code by "
9733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                    << cur_expansion << std::endl;
9743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                method_outlier_expansion[j] = 0.0;  // don't consider this method again
9753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                dumped_values++;
9763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              }
9773a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            }
9783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
9793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
9803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9813a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (skipped_values > 0) {
9823a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << "\t... skipped " << skipped_values
9833a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers           << " methods with expansion > 1 standard deviation from the norm" << std::endl;
9843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
9853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
9863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
9873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
988916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    void Dump(std::ostream& os) {
9893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << "\tart_file_bytes = " << PrettySize(file_bytes) << std::endl << std::endl
9903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << "\tart_file_bytes = header_bytes + object_bytes + alignment_bytes" << std::endl
9913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << StringPrintf("\theader_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
9923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tobject_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
9933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\talignment_bytes =  %8zd (%2.0f%% of art file bytes)\n",
9943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         header_bytes, PercentOfFileBytes(header_bytes),
9953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         object_bytes, PercentOfFileBytes(object_bytes),
9963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         alignment_bytes, PercentOfFileBytes(alignment_bytes))
9973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << std::endl << std::flush;
9983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
999916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      CHECK_EQ(file_bytes, header_bytes + object_bytes + alignment_bytes);
1000916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
1001916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      os << "\tobject_bytes = sum of descriptor_to_bytes values below:\n";
1002916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      size_t object_bytes_total = 0;
1003916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      typedef TableBytes::const_iterator It;  // TODO: C++0x auto
1004916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      for (It it = descriptor_to_bytes.begin(), end = descriptor_to_bytes.end(); it != end; ++it) {
1005955724179c6c739524f610023287f56b24dc31deElliott Hughes        const std::string& descriptor(it->first);
1006916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        size_t bytes = it->second;
1007916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        size_t count = descriptor_to_count[descriptor];
1008916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        double average = static_cast<double>(bytes) / static_cast<double>(count);
1009916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        double percent = PercentOfObjectBytes(bytes);
1010ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes        os << StringPrintf("\t%32s %8zd bytes %6zd instances "
1011916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom                           "(%3.0f bytes/instance) %2.0f%% of object_bytes\n",
1012916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom                           descriptor.c_str(), bytes, count,
1013916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom                           average, percent);
1014916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
1015916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom        object_bytes_total += bytes;
1016916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      }
10173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
1018916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom      CHECK_EQ(object_bytes, object_bytes_total);
1019916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
10203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\tmanaged_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
10213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tmanaged_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
10223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tnative_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n",
10233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         managed_code_bytes, PercentOfOatBytes(managed_code_bytes),
10243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         managed_to_native_code_bytes, PercentOfOatBytes(managed_to_native_code_bytes),
10253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         native_to_managed_code_bytes, PercentOfOatBytes(native_to_managed_code_bytes))
10263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << std::endl << std::flush;
10273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
10283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\tgc_map_bytes           = %7zd (%2.0f%% of oat file_bytes)\n"
10293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tpc_mapping_table_bytes = %7zd (%2.0f%% of oat file_bytes)\n"
10303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         "\tvmap_table_bytes       = %7zd (%2.0f%% of oat file_bytes)\n",
10313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         gc_map_bytes, PercentOfOatBytes(gc_map_bytes),
10323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         pc_mapping_table_bytes, PercentOfOatBytes(pc_mapping_table_bytes),
10333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers                         vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
10343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers         << std::endl << std::flush;
1035916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
1036ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes      os << StringPrintf("\tdex_instruction_bytes = %zd\n", dex_instruction_bytes);
10373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << StringPrintf("\tmanaged_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n",
10383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          static_cast<double>(managed_code_bytes) / static_cast<double>(dex_instruction_bytes),
10393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
10403a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            static_cast<double>(dex_instruction_bytes));
10413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      os << std::endl << std::flush;
10423a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
10433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpOutliers(os);
1044916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom    }
1045916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom  } stats_;
1046916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom
1047916e74e45b60902af342a71bdbfb806ff29c6c2bBrian Carlstrom private:
10483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  UniquePtr<OatDumper> oat_dumper_;
104927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  std::ostream& os_;
10503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const std::string image_filename_;
10513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const std::string host_prefix_;
10523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  Space& image_space_;
10533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  const ImageHeader& image_header_;
1054d1bb4f6b7c8dda429f61937cd42f3a0b7367c271Elliott Hughes
10553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  DISALLOW_COPY_AND_ASSIGN(ImageDumper);
105678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom};
105778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
105878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstromint oatdump(int argc, char** argv) {
105978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  // Skip over argv[0].
106078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  argv++;
106178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  argc--;
106278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
106378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  if (argc == 0) {
1064aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    fprintf(stderr, "No arguments specified\n");
106578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    usage();
106678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
106778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1068aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  const char* oat_filename = NULL;
106978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  const char* image_filename = NULL;
107078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  const char* boot_image_filename = NULL;
107158ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  std::string host_prefix;
107227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  std::ostream* os = &std::cout;
107327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom  UniquePtr<std::ofstream> out;
107478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
107578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  for (int i = 0; i < argc; i++) {
107678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    const StringPiece option(argv[i]);
1077a6cc893c4b142cd410fc956963b6f5a014e983adBrian Carlstrom    if (option.starts_with("--oat-file=")) {
1078a6cc893c4b142cd410fc956963b6f5a014e983adBrian Carlstrom      oat_filename = option.substr(strlen("--oat-file=")).data();
1079aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    } else if (option.starts_with("--image=")) {
108078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      image_filename = option.substr(strlen("--image=")).data();
1081e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom    } else if (option.starts_with("--boot-image=")) {
1082e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom      boot_image_filename = option.substr(strlen("--boot-image=")).data();
108358ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    } else if (option.starts_with("--host-prefix=")) {
108458ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom      host_prefix = option.substr(strlen("--host-prefix=")).data();
108527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom    } else if (option.starts_with("--output=")) {
108627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      const char* filename = option.substr(strlen("--output=")).data();
108727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      out.reset(new std::ofstream(filename));
108827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      if (!out->good()) {
1089aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom        fprintf(stderr, "Failed to open output filename %s\n", filename);
109027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom        usage();
109127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      }
109227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom      os = out.get();
109378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    } else {
1094aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      fprintf(stderr, "Unknown argument %s\n", option.data());
109578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom      usage();
109678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    }
109778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
109878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1099aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (image_filename == NULL && oat_filename == NULL) {
1100362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    fprintf(stderr, "Either --image or --oat must be specified\n");
1101362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    return EXIT_FAILURE;
110278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
110378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1104aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (image_filename != NULL && oat_filename != NULL) {
1105362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    fprintf(stderr, "Either --image or --oat must be specified but not both\n");
1106362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    return EXIT_FAILURE;
1107aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
1108aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
1109aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (oat_filename != NULL) {
11103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, NULL);
1111aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    if (oat_file == NULL) {
1112aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
1113aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      return EXIT_FAILURE;
1114aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
11153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    OatDumper oat_dumper(*oat_file);
11163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    oat_dumper.Dump(*os);
1117aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    return EXIT_SUCCESS;
1118aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
1119aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
112078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  Runtime::Options options;
112178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  std::string image_option;
1122e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  std::string oat_option;
112378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  std::string boot_image_option;
1124e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom  std::string boot_oat_option;
112558ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  if (boot_image_filename != NULL) {
112658ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    boot_image_option += "-Ximage:";
112758ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    boot_image_option += boot_image_filename;
112858ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
112958ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  }
1130aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  if (image_filename != NULL) {
1131aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    image_option += "-Ximage:";
1132aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    image_option += image_filename;
1133aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
1134aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
113558ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom
1136fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom  if (host_prefix.empty()) {
1137fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom    const char* android_product_out = getenv("ANDROID_PRODUCT_OUT");
1138fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom    if (android_product_out != NULL) {
1139fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom        host_prefix = android_product_out;
1140fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom    }
1141fe487d0c789b94e75c93a2b799f1955c3e4edb10Brian Carlstrom  }
114258ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  if (!host_prefix.empty()) {
114358ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    options.push_back(std::make_pair("host-prefix", host_prefix.c_str()));
114478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
114578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
114678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  UniquePtr<Runtime> runtime(Runtime::Create(options, false));
114778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  if (runtime.get() == NULL) {
1148aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    fprintf(stderr, "Failed to create runtime\n");
114978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    return EXIT_FAILURE;
115078128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
115178128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
1152b3bd5f07884f5a1f2b84224363b1372d7c28d447Elliott Hughes  Heap* heap = Runtime::Current()->GetHeap();
1153b3bd5f07884f5a1f2b84224363b1372d7c28d447Elliott Hughes  ImageSpace* image_space = heap->GetSpaces()[heap->GetSpaces().size()-2]->AsImageSpace();
115478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  CHECK(image_space != NULL);
115578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  const ImageHeader& image_header = image_space->GetImageHeader();
115678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  if (!image_header.IsValid()) {
1157aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    fprintf(stderr, "Invalid image header %s\n", image_filename);
115878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom    return EXIT_FAILURE;
115978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  }
11603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  ImageDumper image_dumper(*os, image_filename, host_prefix, *image_space, image_header);
11613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  image_dumper.Dump();
116278128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  return EXIT_SUCCESS;
116378128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom}
116478128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
116578128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom} // namespace art
116678128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom
116778128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstromint main(int argc, char** argv) {
116878128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom  return art::oatdump(argc, argv);
116978128a63b2615744760b7f8ab83df9764a5d4a95Brian Carlstrom}
1170