Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "code-stubs.h"
     31 #include "codegen-inl.h"
     32 #include "debug.h"
     33 #include "disasm.h"
     34 #include "disassembler.h"
     35 #include "macro-assembler.h"
     36 #include "serialize.h"
     37 #include "string-stream.h"
     38 
     39 namespace v8 {
     40 namespace internal {
     41 
     42 #ifdef ENABLE_DISASSEMBLER
     43 
     44 void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
     45   for (byte* pc = begin; pc < end; pc++) {
     46     if (f == NULL) {
     47       PrintF("%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n", pc, pc - begin, *pc);
     48     } else {
     49       fprintf(f, "%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
     50               reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
     51     }
     52   }
     53 }
     54 
     55 
     56 class V8NameConverter: public disasm::NameConverter {
     57  public:
     58   explicit V8NameConverter(Code* code) : code_(code) {}
     59   virtual const char* NameOfAddress(byte* pc) const;
     60   virtual const char* NameInCode(byte* addr) const;
     61   Code* code() const { return code_; }
     62  private:
     63   Code* code_;
     64 };
     65 
     66 
     67 const char* V8NameConverter::NameOfAddress(byte* pc) const {
     68   static v8::internal::EmbeddedVector<char, 128> buffer;
     69 
     70   const char* name = Builtins::Lookup(pc);
     71   if (name != NULL) {
     72     OS::SNPrintF(buffer, "%s  (%p)", name, pc);
     73     return buffer.start();
     74   }
     75 
     76   if (code_ != NULL) {
     77     int offs = static_cast<int>(pc - code_->instruction_start());
     78     // print as code offset, if it seems reasonable
     79     if (0 <= offs && offs < code_->instruction_size()) {
     80       OS::SNPrintF(buffer, "%d  (%p)", offs, pc);
     81       return buffer.start();
     82     }
     83   }
     84 
     85   return disasm::NameConverter::NameOfAddress(pc);
     86 }
     87 
     88 
     89 const char* V8NameConverter::NameInCode(byte* addr) const {
     90   // The V8NameConverter is used for well known code, so we can "safely"
     91   // dereference pointers in generated code.
     92   return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : "";
     93 }
     94 
     95 
     96 static void DumpBuffer(FILE* f, char* buff) {
     97   if (f == NULL) {
     98     PrintF("%s", buff);
     99   } else {
    100     fprintf(f, "%s", buff);
    101   }
    102 }
    103 
    104 static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
    105 static const int kRelocInfoPosition = 57;
    106 
    107 static int DecodeIt(FILE* f,
    108                     const V8NameConverter& converter,
    109                     byte* begin,
    110                     byte* end) {
    111   NoHandleAllocation ha;
    112   AssertNoAllocation no_alloc;
    113   ExternalReferenceEncoder ref_encoder;
    114 
    115   v8::internal::EmbeddedVector<char, 128> decode_buffer;
    116   v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
    117   byte* pc = begin;
    118   disasm::Disassembler d(converter);
    119   RelocIterator* it = NULL;
    120   if (converter.code() != NULL) {
    121     it = new RelocIterator(converter.code());
    122   } else {
    123     // No relocation information when printing code stubs.
    124   }
    125   int constants = -1;  // no constants being decoded at the start
    126 
    127   while (pc < end) {
    128     // First decode instruction so that we know its length.
    129     byte* prev_pc = pc;
    130     if (constants > 0) {
    131       OS::SNPrintF(decode_buffer,
    132                    "%08x       constant",
    133                    *reinterpret_cast<int32_t*>(pc));
    134       constants--;
    135       pc += 4;
    136     } else {
    137       int num_const = d.ConstantPoolSizeAt(pc);
    138       if (num_const >= 0) {
    139         OS::SNPrintF(decode_buffer,
    140                      "%08x       constant pool begin",
    141                      *reinterpret_cast<int32_t*>(pc));
    142         constants = num_const;
    143         pc += 4;
    144       } else if (it != NULL && !it->done() && it->rinfo()->pc() == pc &&
    145           it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
    146         // raw pointer embedded in code stream, e.g., jump table
    147         byte* ptr = *reinterpret_cast<byte**>(pc);
    148         OS::SNPrintF(decode_buffer,
    149                      "%08" V8PRIxPTR "      jump table entry %4" V8PRIdPTR,
    150                      ptr,
    151                      ptr - begin);
    152         pc += 4;
    153       } else {
    154         decode_buffer[0] = '\0';
    155         pc += d.InstructionDecode(decode_buffer, pc);
    156       }
    157     }
    158 
    159     // Collect RelocInfo for this instruction (prev_pc .. pc-1)
    160     List<const char*> comments(4);
    161     List<byte*> pcs(1);
    162     List<RelocInfo::Mode> rmodes(1);
    163     List<intptr_t> datas(1);
    164     if (it != NULL) {
    165       while (!it->done() && it->rinfo()->pc() < pc) {
    166         if (RelocInfo::IsComment(it->rinfo()->rmode())) {
    167           // For comments just collect the text.
    168           comments.Add(reinterpret_cast<const char*>(it->rinfo()->data()));
    169         } else {
    170           // For other reloc info collect all data.
    171           pcs.Add(it->rinfo()->pc());
    172           rmodes.Add(it->rinfo()->rmode());
    173           datas.Add(it->rinfo()->data());
    174         }
    175         it->next();
    176       }
    177     }
    178 
    179     StringBuilder out(out_buffer.start(), out_buffer.length());
    180 
    181     // Comments.
    182     for (int i = 0; i < comments.length(); i++) {
    183       out.AddFormatted("                  %s\n", comments[i]);
    184     }
    185 
    186     // Write out comments, resets outp so that we can format the next line.
    187     DumpBuffer(f, out.Finalize());
    188     out.Reset();
    189 
    190     // Instruction address and instruction offset.
    191     out.AddFormatted("%p  %4d  ", prev_pc, prev_pc - begin);
    192 
    193     // Instruction.
    194     out.AddFormatted("%s", decode_buffer.start());
    195 
    196     // Print all the reloc info for this instruction which are not comments.
    197     for (int i = 0; i < pcs.length(); i++) {
    198       // Put together the reloc info
    199       RelocInfo relocinfo(pcs[i], rmodes[i], datas[i]);
    200 
    201       // Indent the printing of the reloc info.
    202       if (i == 0) {
    203         // The first reloc info is printed after the disassembled instruction.
    204         out.AddPadding(' ', kRelocInfoPosition - out.position());
    205       } else {
    206         // Additional reloc infos are printed on separate lines.
    207         out.AddFormatted("\n");
    208         out.AddPadding(' ', kRelocInfoPosition);
    209       }
    210 
    211       RelocInfo::Mode rmode = relocinfo.rmode();
    212       if (RelocInfo::IsPosition(rmode)) {
    213         if (RelocInfo::IsStatementPosition(rmode)) {
    214           out.AddFormatted("    ;; debug: statement %d", relocinfo.data());
    215         } else {
    216           out.AddFormatted("    ;; debug: position %d", relocinfo.data());
    217         }
    218       } else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
    219         HeapStringAllocator allocator;
    220         StringStream accumulator(&allocator);
    221         relocinfo.target_object()->ShortPrint(&accumulator);
    222         SmartPointer<const char> obj_name = accumulator.ToCString();
    223         out.AddFormatted("    ;; object: %s", *obj_name);
    224       } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
    225         const char* reference_name =
    226             ref_encoder.NameOfAddress(*relocinfo.target_reference_address());
    227         out.AddFormatted("    ;; external reference (%s)", reference_name);
    228       } else if (RelocInfo::IsCodeTarget(rmode)) {
    229         out.AddFormatted("    ;; code:");
    230         if (rmode == RelocInfo::CONSTRUCT_CALL) {
    231           out.AddFormatted(" constructor,");
    232         }
    233         Code* code = Code::GetCodeFromTargetAddress(relocinfo.target_address());
    234         Code::Kind kind = code->kind();
    235         if (code->is_inline_cache_stub()) {
    236           if (rmode == RelocInfo::CODE_TARGET_CONTEXT) {
    237             out.AddFormatted(" contextual,");
    238           }
    239           InlineCacheState ic_state = code->ic_state();
    240           out.AddFormatted(" %s, %s", Code::Kind2String(kind),
    241               Code::ICState2String(ic_state));
    242           if (ic_state == MONOMORPHIC) {
    243             PropertyType type = code->type();
    244             out.AddFormatted(", %s", Code::PropertyType2String(type));
    245           }
    246           if (code->ic_in_loop() == IN_LOOP) {
    247             out.AddFormatted(", in_loop");
    248           }
    249           if (kind == Code::CALL_IC) {
    250             out.AddFormatted(", argc = %d", code->arguments_count());
    251           }
    252         } else if (kind == Code::STUB) {
    253           // Reverse lookup required as the minor key cannot be retrieved
    254           // from the code object.
    255           Object* obj = Heap::code_stubs()->SlowReverseLookup(code);
    256           if (obj != Heap::undefined_value()) {
    257             ASSERT(obj->IsSmi());
    258             // Get the STUB key and extract major and minor key.
    259             uint32_t key = Smi::cast(obj)->value();
    260             uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
    261             ASSERT(code->major_key() == CodeStub::MajorKeyFromKey(key));
    262             out.AddFormatted(" %s, %s, ",
    263                              Code::Kind2String(kind),
    264                              CodeStub::MajorName(code->major_key(), false));
    265             switch (code->major_key()) {
    266               case CodeStub::CallFunction:
    267                 out.AddFormatted("argc = %d", minor_key);
    268                 break;
    269             default:
    270                 out.AddFormatted("minor: %d", minor_key);
    271             }
    272           }
    273         } else {
    274           out.AddFormatted(" %s", Code::Kind2String(kind));
    275         }
    276       } else {
    277         out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
    278       }
    279     }
    280     out.AddString("\n");
    281     DumpBuffer(f, out.Finalize());
    282     out.Reset();
    283   }
    284 
    285   delete it;
    286   return static_cast<int>(pc - begin);
    287 }
    288 
    289 
    290 int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
    291   V8NameConverter defaultConverter(NULL);
    292   return DecodeIt(f, defaultConverter, begin, end);
    293 }
    294 
    295 
    296 // Called by Code::CodePrint.
    297 void Disassembler::Decode(FILE* f, Code* code) {
    298   byte* begin = Code::cast(code)->instruction_start();
    299   byte* end = begin + Code::cast(code)->instruction_size();
    300   V8NameConverter v8NameConverter(code);
    301   DecodeIt(f, v8NameConverter, begin, end);
    302 }
    303 
    304 #else  // ENABLE_DISASSEMBLER
    305 
    306 void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
    307 int Disassembler::Decode(FILE* f, byte* begin, byte* end) { return 0; }
    308 void Disassembler::Decode(FILE* f, Code* code) {}
    309 
    310 #endif  // ENABLE_DISASSEMBLER
    311 
    312 } }  // namespace v8::internal
    313