• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #include "src/code-stubs.h"
8 #include "src/codegen.h"
9 #include "src/debug.h"
10 #include "src/deoptimizer.h"
11 #include "src/disasm.h"
12 #include "src/disassembler.h"
13 #include "src/macro-assembler.h"
14 #include "src/serialize.h"
15 #include "src/string-stream.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 #ifdef ENABLE_DISASSEMBLER
21 
Dump(FILE * f,byte * begin,byte * end)22 void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
23   for (byte* pc = begin; pc < end; pc++) {
24     if (f == NULL) {
25       PrintF("%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
26              reinterpret_cast<intptr_t>(pc),
27              pc - begin,
28              *pc);
29     } else {
30       PrintF(f, "%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
31              reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
32     }
33   }
34 }
35 
36 
37 class V8NameConverter: public disasm::NameConverter {
38  public:
V8NameConverter(Code * code)39   explicit V8NameConverter(Code* code) : code_(code) {}
40   virtual const char* NameOfAddress(byte* pc) const;
41   virtual const char* NameInCode(byte* addr) const;
code() const42   Code* code() const { return code_; }
43  private:
44   Code* code_;
45 
46   EmbeddedVector<char, 128> v8_buffer_;
47 };
48 
49 
NameOfAddress(byte * pc) const50 const char* V8NameConverter::NameOfAddress(byte* pc) const {
51   const char* name = code_->GetIsolate()->builtins()->Lookup(pc);
52   if (name != NULL) {
53     SNPrintF(v8_buffer_, "%s  (%p)", name, pc);
54     return v8_buffer_.start();
55   }
56 
57   if (code_ != NULL) {
58     int offs = static_cast<int>(pc - code_->instruction_start());
59     // print as code offset, if it seems reasonable
60     if (0 <= offs && offs < code_->instruction_size()) {
61       SNPrintF(v8_buffer_, "%d  (%p)", offs, pc);
62       return v8_buffer_.start();
63     }
64   }
65 
66   return disasm::NameConverter::NameOfAddress(pc);
67 }
68 
69 
NameInCode(byte * addr) const70 const char* V8NameConverter::NameInCode(byte* addr) const {
71   // The V8NameConverter is used for well known code, so we can "safely"
72   // dereference pointers in generated code.
73   return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : "";
74 }
75 
76 
DumpBuffer(FILE * f,StringBuilder * out)77 static void DumpBuffer(FILE* f, StringBuilder* out) {
78   if (f == NULL) {
79     PrintF("%s\n", out->Finalize());
80   } else {
81     PrintF(f, "%s\n", out->Finalize());
82   }
83   out->Reset();
84 }
85 
86 
87 static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
88 static const int kRelocInfoPosition = 57;
89 
DecodeIt(Isolate * isolate,FILE * f,const V8NameConverter & converter,byte * begin,byte * end)90 static int DecodeIt(Isolate* isolate,
91                     FILE* f,
92                     const V8NameConverter& converter,
93                     byte* begin,
94                     byte* end) {
95   SealHandleScope shs(isolate);
96   DisallowHeapAllocation no_alloc;
97   ExternalReferenceEncoder ref_encoder(isolate);
98 
99   v8::internal::EmbeddedVector<char, 128> decode_buffer;
100   v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
101   StringBuilder out(out_buffer.start(), out_buffer.length());
102   byte* pc = begin;
103   disasm::Disassembler d(converter);
104   RelocIterator* it = NULL;
105   if (converter.code() != NULL) {
106     it = new RelocIterator(converter.code());
107   } else {
108     // No relocation information when printing code stubs.
109   }
110   int constants = -1;  // no constants being decoded at the start
111 
112   while (pc < end) {
113     // First decode instruction so that we know its length.
114     byte* prev_pc = pc;
115     if (constants > 0) {
116       SNPrintF(decode_buffer,
117                "%08x       constant",
118                *reinterpret_cast<int32_t*>(pc));
119       constants--;
120       pc += 4;
121     } else {
122       int num_const = d.ConstantPoolSizeAt(pc);
123       if (num_const >= 0) {
124         SNPrintF(decode_buffer,
125                  "%08x       constant pool begin",
126                  *reinterpret_cast<int32_t*>(pc));
127         constants = num_const;
128         pc += 4;
129       } else if (it != NULL && !it->done() && it->rinfo()->pc() == pc &&
130           it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
131         // raw pointer embedded in code stream, e.g., jump table
132         byte* ptr = *reinterpret_cast<byte**>(pc);
133         SNPrintF(decode_buffer,
134                  "%08" V8PRIxPTR "      jump table entry %4" V8PRIdPTR,
135                  reinterpret_cast<intptr_t>(ptr),
136                  ptr - begin);
137         pc += 4;
138       } else {
139         decode_buffer[0] = '\0';
140         pc += d.InstructionDecode(decode_buffer, pc);
141       }
142     }
143 
144     // Collect RelocInfo for this instruction (prev_pc .. pc-1)
145     List<const char*> comments(4);
146     List<byte*> pcs(1);
147     List<RelocInfo::Mode> rmodes(1);
148     List<intptr_t> datas(1);
149     if (it != NULL) {
150       while (!it->done() && it->rinfo()->pc() < pc) {
151         if (RelocInfo::IsComment(it->rinfo()->rmode())) {
152           // For comments just collect the text.
153           comments.Add(reinterpret_cast<const char*>(it->rinfo()->data()));
154         } else {
155           // For other reloc info collect all data.
156           pcs.Add(it->rinfo()->pc());
157           rmodes.Add(it->rinfo()->rmode());
158           datas.Add(it->rinfo()->data());
159         }
160         it->next();
161       }
162     }
163 
164     // Comments.
165     for (int i = 0; i < comments.length(); i++) {
166       out.AddFormatted("                  %s", comments[i]);
167       DumpBuffer(f, &out);
168     }
169 
170     // Instruction address and instruction offset.
171     out.AddFormatted("%p  %4d  ", prev_pc, prev_pc - begin);
172 
173     // Instruction.
174     out.AddFormatted("%s", decode_buffer.start());
175 
176     // Print all the reloc info for this instruction which are not comments.
177     for (int i = 0; i < pcs.length(); i++) {
178       // Put together the reloc info
179       RelocInfo relocinfo(pcs[i], rmodes[i], datas[i], converter.code());
180 
181       // Indent the printing of the reloc info.
182       if (i == 0) {
183         // The first reloc info is printed after the disassembled instruction.
184         out.AddPadding(' ', kRelocInfoPosition - out.position());
185       } else {
186         // Additional reloc infos are printed on separate lines.
187         DumpBuffer(f, &out);
188         out.AddPadding(' ', kRelocInfoPosition);
189       }
190 
191       RelocInfo::Mode rmode = relocinfo.rmode();
192       if (RelocInfo::IsPosition(rmode)) {
193         if (RelocInfo::IsStatementPosition(rmode)) {
194           out.AddFormatted("    ;; debug: statement %d", relocinfo.data());
195         } else {
196           out.AddFormatted("    ;; debug: position %d", relocinfo.data());
197         }
198       } else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
199         HeapStringAllocator allocator;
200         StringStream accumulator(&allocator);
201         relocinfo.target_object()->ShortPrint(&accumulator);
202         SmartArrayPointer<const char> obj_name = accumulator.ToCString();
203         out.AddFormatted("    ;; object: %s", obj_name.get());
204       } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
205         const char* reference_name =
206             ref_encoder.NameOfAddress(relocinfo.target_reference());
207         out.AddFormatted("    ;; external reference (%s)", reference_name);
208       } else if (RelocInfo::IsCodeTarget(rmode)) {
209         out.AddFormatted("    ;; code:");
210         if (rmode == RelocInfo::CONSTRUCT_CALL) {
211           out.AddFormatted(" constructor,");
212         }
213         Code* code = Code::GetCodeFromTargetAddress(relocinfo.target_address());
214         Code::Kind kind = code->kind();
215         if (code->is_inline_cache_stub()) {
216           if (kind == Code::LOAD_IC &&
217               LoadICState::GetContextualMode(code->extra_ic_state()) ==
218                   CONTEXTUAL) {
219             out.AddFormatted(" contextual,");
220           }
221           InlineCacheState ic_state = code->ic_state();
222           out.AddFormatted(" %s, %s", Code::Kind2String(kind),
223               Code::ICState2String(ic_state));
224           if (ic_state == MONOMORPHIC) {
225             Code::StubType type = code->type();
226             out.AddFormatted(", %s", Code::StubType2String(type));
227           }
228         } else if (kind == Code::STUB || kind == Code::HANDLER) {
229           // Get the STUB key and extract major and minor key.
230           uint32_t key = code->stub_key();
231           uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
232           CodeStub::Major major_key = CodeStub::GetMajorKey(code);
233           DCHECK(major_key == CodeStub::MajorKeyFromKey(key));
234           out.AddFormatted(" %s, %s, ", Code::Kind2String(kind),
235                            CodeStub::MajorName(major_key, false));
236           switch (major_key) {
237             case CodeStub::CallFunction: {
238               int argc = CallFunctionStub::ExtractArgcFromMinorKey(minor_key);
239               out.AddFormatted("argc = %d", argc);
240               break;
241             }
242             default:
243               out.AddFormatted("minor: %d", minor_key);
244           }
245         } else {
246           out.AddFormatted(" %s", Code::Kind2String(kind));
247         }
248         if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
249           out.AddFormatted(" (id = %d)", static_cast<int>(relocinfo.data()));
250         }
251       } else if (RelocInfo::IsRuntimeEntry(rmode) &&
252                  isolate->deoptimizer_data() != NULL) {
253         // A runtime entry reloinfo might be a deoptimization bailout.
254         Address addr = relocinfo.target_address();
255         int id = Deoptimizer::GetDeoptimizationId(isolate,
256                                                   addr,
257                                                   Deoptimizer::EAGER);
258         if (id == Deoptimizer::kNotDeoptimizationEntry) {
259           id = Deoptimizer::GetDeoptimizationId(isolate,
260                                                 addr,
261                                                 Deoptimizer::LAZY);
262           if (id == Deoptimizer::kNotDeoptimizationEntry) {
263             id = Deoptimizer::GetDeoptimizationId(isolate,
264                                                   addr,
265                                                   Deoptimizer::SOFT);
266             if (id == Deoptimizer::kNotDeoptimizationEntry) {
267               out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
268             } else {
269               out.AddFormatted("    ;; soft deoptimization bailout %d", id);
270             }
271           } else {
272             out.AddFormatted("    ;; lazy deoptimization bailout %d", id);
273           }
274         } else {
275           out.AddFormatted("    ;; deoptimization bailout %d", id);
276         }
277       } else {
278         out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
279       }
280     }
281     DumpBuffer(f, &out);
282   }
283 
284   // Emit comments following the last instruction (if any).
285   if (it != NULL) {
286     for ( ; !it->done(); it->next()) {
287       if (RelocInfo::IsComment(it->rinfo()->rmode())) {
288         out.AddFormatted("                  %s",
289                          reinterpret_cast<const char*>(it->rinfo()->data()));
290         DumpBuffer(f, &out);
291       }
292     }
293   }
294 
295   delete it;
296   return static_cast<int>(pc - begin);
297 }
298 
299 
Decode(Isolate * isolate,FILE * f,byte * begin,byte * end)300 int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
301   V8NameConverter defaultConverter(NULL);
302   return DecodeIt(isolate, f, defaultConverter, begin, end);
303 }
304 
305 
306 // Called by Code::CodePrint.
Decode(FILE * f,Code * code)307 void Disassembler::Decode(FILE* f, Code* code) {
308   Isolate* isolate = code->GetIsolate();
309   int decode_size = code->is_crankshafted()
310       ? static_cast<int>(code->safepoint_table_offset())
311       : code->instruction_size();
312   // If there might be a back edge table, stop before reaching it.
313   if (code->kind() == Code::FUNCTION) {
314     decode_size =
315         Min(decode_size, static_cast<int>(code->back_edge_table_offset()));
316   }
317 
318   byte* begin = code->instruction_start();
319   byte* end = begin + decode_size;
320   V8NameConverter v8NameConverter(code);
321   DecodeIt(isolate, f, v8NameConverter, begin, end);
322 }
323 
324 #else  // ENABLE_DISASSEMBLER
325 
326 void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
327 int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
328   return 0;
329 }
330 
331 
332 void Disassembler::Decode(FILE* f, Code* code) {}
333 
334 #endif  // ENABLE_DISASSEMBLER
335 
336 } }  // namespace v8::internal
337