• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Dump(FILE * f,byte * begin,byte * end)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:
V8NameConverter(Code * code)58   explicit V8NameConverter(Code* code) : code_(code) {}
59   virtual const char* NameOfAddress(byte* pc) const;
60   virtual const char* NameInCode(byte* addr) const;
code() const61   Code* code() const { return code_; }
62  private:
63   Code* code_;
64 };
65 
66 
NameOfAddress(byte * pc) const67 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 
NameInCode(byte * addr) const89 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 
DumpBuffer(FILE * f,char * buff)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 
DecodeIt(FILE * f,const V8NameConverter & converter,byte * begin,byte * end)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 
Decode(FILE * f,byte * begin,byte * end)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.
Decode(FILE * f,Code * code)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