v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
disassembler.cc
Go to the documentation of this file.
1 // Copyright 2011 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.h"
32 #include "debug.h"
33 #include "deoptimizer.h"
34 #include "disasm.h"
35 #include "disassembler.h"
36 #include "macro-assembler.h"
37 #include "serialize.h"
38 #include "string-stream.h"
39 
40 namespace v8 {
41 namespace internal {
42 
43 #ifdef ENABLE_DISASSEMBLER
44 
45 void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
46  for (byte* pc = begin; pc < end; pc++) {
47  if (f == NULL) {
48  PrintF("%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
49  reinterpret_cast<intptr_t>(pc),
50  pc - begin,
51  *pc);
52  } else {
53  fprintf(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n",
54  reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
55  }
56  }
57 }
58 
59 
60 class V8NameConverter: public disasm::NameConverter {
61  public:
62  explicit V8NameConverter(Code* code) : code_(code) {}
63  virtual const char* NameOfAddress(byte* pc) const;
64  virtual const char* NameInCode(byte* addr) const;
65  Code* code() const { return code_; }
66  private:
67  Code* code_;
68 
69  EmbeddedVector<char, 128> v8_buffer_;
70 };
71 
72 
73 const char* V8NameConverter::NameOfAddress(byte* pc) const {
74  const char* name = Isolate::Current()->builtins()->Lookup(pc);
75  if (name != NULL) {
76  OS::SNPrintF(v8_buffer_, "%s (%p)", name, pc);
77  return v8_buffer_.start();
78  }
79 
80  if (code_ != NULL) {
81  int offs = static_cast<int>(pc - code_->instruction_start());
82  // print as code offset, if it seems reasonable
83  if (0 <= offs && offs < code_->instruction_size()) {
84  OS::SNPrintF(v8_buffer_, "%d (%p)", offs, pc);
85  return v8_buffer_.start();
86  }
87  }
88 
90 }
91 
92 
93 const char* V8NameConverter::NameInCode(byte* addr) const {
94  // The V8NameConverter is used for well known code, so we can "safely"
95  // dereference pointers in generated code.
96  return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : "";
97 }
98 
99 
100 static void DumpBuffer(FILE* f, StringBuilder* out) {
101  if (f == NULL) {
102  PrintF("%s\n", out->Finalize());
103  } else {
104  fprintf(f, "%s\n", out->Finalize());
105  }
106  out->Reset();
107 }
108 
109 
110 
111 static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
112 static const int kRelocInfoPosition = 57;
113 
114 static int DecodeIt(FILE* f,
115  const V8NameConverter& converter,
116  byte* begin,
117  byte* end) {
118  NoHandleAllocation ha;
119  AssertNoAllocation no_alloc;
120  ExternalReferenceEncoder ref_encoder;
121  Heap* heap = HEAP;
122 
125  StringBuilder out(out_buffer.start(), out_buffer.length());
126  byte* pc = begin;
127  disasm::Disassembler d(converter);
128  RelocIterator* it = NULL;
129  if (converter.code() != NULL) {
130  it = new RelocIterator(converter.code());
131  } else {
132  // No relocation information when printing code stubs.
133  }
134  int constants = -1; // no constants being decoded at the start
135 
136  while (pc < end) {
137  // First decode instruction so that we know its length.
138  byte* prev_pc = pc;
139  if (constants > 0) {
140  OS::SNPrintF(decode_buffer,
141  "%08x constant",
142  *reinterpret_cast<int32_t*>(pc));
143  constants--;
144  pc += 4;
145  } else {
146  int num_const = d.ConstantPoolSizeAt(pc);
147  if (num_const >= 0) {
148  OS::SNPrintF(decode_buffer,
149  "%08x constant pool begin",
150  *reinterpret_cast<int32_t*>(pc));
151  constants = num_const;
152  pc += 4;
153  } else if (it != NULL && !it->done() && it->rinfo()->pc() == pc &&
154  it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
155  // raw pointer embedded in code stream, e.g., jump table
156  byte* ptr = *reinterpret_cast<byte**>(pc);
157  OS::SNPrintF(decode_buffer,
158  "%08" V8PRIxPTR " jump table entry %4" V8PRIdPTR,
159  ptr,
160  ptr - begin);
161  pc += 4;
162  } else {
163  decode_buffer[0] = '\0';
164  pc += d.InstructionDecode(decode_buffer, pc);
165  }
166  }
167 
168  // Collect RelocInfo for this instruction (prev_pc .. pc-1)
169  List<const char*> comments(4);
170  List<byte*> pcs(1);
171  List<RelocInfo::Mode> rmodes(1);
172  List<intptr_t> datas(1);
173  if (it != NULL) {
174  while (!it->done() && it->rinfo()->pc() < pc) {
175  if (RelocInfo::IsComment(it->rinfo()->rmode())) {
176  // For comments just collect the text.
177  comments.Add(reinterpret_cast<const char*>(it->rinfo()->data()));
178  } else {
179  // For other reloc info collect all data.
180  pcs.Add(it->rinfo()->pc());
181  rmodes.Add(it->rinfo()->rmode());
182  datas.Add(it->rinfo()->data());
183  }
184  it->next();
185  }
186  }
187 
188  // Comments.
189  for (int i = 0; i < comments.length(); i++) {
190  out.AddFormatted(" %s", comments[i]);
191  DumpBuffer(f, &out);
192  }
193 
194  // Instruction address and instruction offset.
195  out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin);
196 
197  // Instruction.
198  out.AddFormatted("%s", decode_buffer.start());
199 
200  // Print all the reloc info for this instruction which are not comments.
201  for (int i = 0; i < pcs.length(); i++) {
202  // Put together the reloc info
203  RelocInfo relocinfo(pcs[i], rmodes[i], datas[i], NULL);
204 
205  // Indent the printing of the reloc info.
206  if (i == 0) {
207  // The first reloc info is printed after the disassembled instruction.
208  out.AddPadding(' ', kRelocInfoPosition - out.position());
209  } else {
210  // Additional reloc infos are printed on separate lines.
211  DumpBuffer(f, &out);
212  out.AddPadding(' ', kRelocInfoPosition);
213  }
214 
215  RelocInfo::Mode rmode = relocinfo.rmode();
216  if (RelocInfo::IsPosition(rmode)) {
217  if (RelocInfo::IsStatementPosition(rmode)) {
218  out.AddFormatted(" ;; debug: statement %d", relocinfo.data());
219  } else {
220  out.AddFormatted(" ;; debug: position %d", relocinfo.data());
221  }
222  } else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
223  HeapStringAllocator allocator;
224  StringStream accumulator(&allocator);
225  relocinfo.target_object()->ShortPrint(&accumulator);
226  SmartArrayPointer<const char> obj_name = accumulator.ToCString();
227  out.AddFormatted(" ;; object: %s", *obj_name);
228  } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
229  const char* reference_name =
230  ref_encoder.NameOfAddress(*relocinfo.target_reference_address());
231  out.AddFormatted(" ;; external reference (%s)", reference_name);
232  } else if (RelocInfo::IsCodeTarget(rmode)) {
233  out.AddFormatted(" ;; code:");
234  if (rmode == RelocInfo::CONSTRUCT_CALL) {
235  out.AddFormatted(" constructor,");
236  }
237  Code* code = Code::GetCodeFromTargetAddress(relocinfo.target_address());
238  Code::Kind kind = code->kind();
239  if (code->is_inline_cache_stub()) {
240  if (rmode == RelocInfo::CODE_TARGET_CONTEXT) {
241  out.AddFormatted(" contextual,");
242  }
243  InlineCacheState ic_state = code->ic_state();
244  out.AddFormatted(" %s, %s", Code::Kind2String(kind),
245  Code::ICState2String(ic_state));
246  if (ic_state == MONOMORPHIC) {
247  Code::StubType type = code->type();
248  out.AddFormatted(", %s", Code::StubType2String(type));
249  }
250  if (kind == Code::CALL_IC || kind == Code::KEYED_CALL_IC) {
251  out.AddFormatted(", argc = %d", code->arguments_count());
252  }
253  } else if (kind == Code::STUB) {
254  // Reverse lookup required as the minor key cannot be retrieved
255  // from the code object.
256  Object* obj = heap->code_stubs()->SlowReverseLookup(code);
257  if (obj != heap->undefined_value()) {
258  ASSERT(obj->IsSmi());
259  // Get the STUB key and extract major and minor key.
260  uint32_t key = Smi::cast(obj)->value();
261  uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
262  CodeStub::Major major_key = CodeStub::GetMajorKey(code);
263  ASSERT(major_key == CodeStub::MajorKeyFromKey(key));
264  out.AddFormatted(" %s, %s, ",
265  Code::Kind2String(kind),
266  CodeStub::MajorName(major_key, false));
267  switch (major_key) {
268  case CodeStub::CallFunction: {
269  int argc =
271  out.AddFormatted("argc = %d", argc);
272  break;
273  }
274  default:
275  out.AddFormatted("minor: %d", minor_key);
276  }
277  }
278  } else {
279  out.AddFormatted(" %s", Code::Kind2String(kind));
280  }
281  if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
282  out.AddFormatted(" (id = %d)", static_cast<int>(relocinfo.data()));
283  }
284  } else if (rmode == RelocInfo::RUNTIME_ENTRY &&
285  Isolate::Current()->deoptimizer_data() != NULL) {
286  // A runtime entry reloinfo might be a deoptimization bailout.
287  Address addr = relocinfo.target_address();
290  out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
291  } else {
292  out.AddFormatted(" ;; deoptimization bailout %d", id);
293  }
294  } else {
295  out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
296  }
297  }
298  DumpBuffer(f, &out);
299  }
300 
301  // Emit comments following the last instruction (if any).
302  if (it != NULL) {
303  for ( ; !it->done(); it->next()) {
304  if (RelocInfo::IsComment(it->rinfo()->rmode())) {
305  out.AddFormatted(" %s",
306  reinterpret_cast<const char*>(it->rinfo()->data()));
307  DumpBuffer(f, &out);
308  }
309  }
310  }
311 
312  delete it;
313  return static_cast<int>(pc - begin);
314 }
315 
316 
317 int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
318  V8NameConverter defaultConverter(NULL);
319  return DecodeIt(f, defaultConverter, begin, end);
320 }
321 
322 
323 // Called by Code::CodePrint.
324 void Disassembler::Decode(FILE* f, Code* code) {
325  int decode_size = (code->kind() == Code::OPTIMIZED_FUNCTION)
326  ? static_cast<int>(code->safepoint_table_offset())
327  : code->instruction_size();
328  // If there might be a stack check table, stop before reaching it.
329  if (code->kind() == Code::FUNCTION) {
330  decode_size =
331  Min(decode_size, static_cast<int>(code->stack_check_table_offset()));
332  }
333 
334  byte* begin = code->instruction_start();
335  byte* end = begin + decode_size;
336  V8NameConverter v8NameConverter(code);
337  DecodeIt(f, v8NameConverter, begin, end);
338 }
339 
340 #else // ENABLE_DISASSEMBLER
341 
342 void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
343 int Disassembler::Decode(FILE* f, byte* begin, byte* end) { return 0; }
344 void Disassembler::Decode(FILE* f, Code* code) {}
345 
346 #endif // ENABLE_DISASSEMBLER
347 
348 } } // namespace v8::internal
byte * Address
Definition: globals.h:157
#define V8PRIxPTR
Definition: globals.h:189
void PrintF(const char *format,...)
Definition: v8utils.cc:40
static int ExtractArgcFromMinorKey(int minor_key)
Definition: code-stubs.h:758
#define ASSERT(condition)
Definition: checks.h:270
static Smi * cast(Object *object)
uint8_t byte
Definition: globals.h:156
T * start() const
Definition: utils.h:390
const Register pc
int length() const
Definition: utils.h:384
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:3559
virtual const char * NameOfAddress(byte *addr) const
#define V8PRIdPTR
Definition: globals.h:190
static const int kMaxShortPrintLength
Definition: objects.h:7393
static int SNPrintF(Vector< char > str, const char *format,...)
static const int kNotDeoptimizationEntry
Definition: deoptimizer.h:248
#define HEAP
Definition: isolate.h:1433
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
#define RUNTIME_ENTRY(name, nargs, ressize)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
static int Decode(FILE *f, byte *begin, byte *end)
T Min(T a, T b)
Definition: utils.h:229
static void Dump(FILE *f, byte *begin, byte *end)
static int GetDeoptimizationId(Address addr, BailoutType type)
Definition: deoptimizer.cc:478