The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / disassembler.cc @ f230a1cf

History | View | Annotate | Download (13.4 KB)

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
      PrintF(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 = code_->GetIsolate()->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

    
89
  return disasm::NameConverter::NameOfAddress(pc);
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
    PrintF(f, "%s\n", out->Finalize());
105
  }
106
  out->Reset();
107
}
108

    
109

    
110
static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
111
static const int kRelocInfoPosition = 57;
112

    
113
static int DecodeIt(Isolate* isolate,
114
                    FILE* f,
115
                    const V8NameConverter& converter,
116
                    byte* begin,
117
                    byte* end) {
118
  SealHandleScope shs(isolate);
119
  DisallowHeapAllocation no_alloc;
120
  ExternalReferenceEncoder ref_encoder(isolate);
121
  Heap* heap = isolate->heap();
122

    
123
  v8::internal::EmbeddedVector<char, 128> decode_buffer;
124
  v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
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 || kind == Code::HANDLER) {
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 =
270
                    CallFunctionStub::ExtractArgcFromMinorKey(minor_key);
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 (RelocInfo::IsRuntimeEntry(rmode) &&
285
                 isolate->deoptimizer_data() != NULL) {
286
        // A runtime entry reloinfo might be a deoptimization bailout.
287
        Address addr = relocinfo.target_address();
288
        int id = Deoptimizer::GetDeoptimizationId(isolate,
289
                                                  addr,
290
                                                  Deoptimizer::EAGER);
291
        if (id == Deoptimizer::kNotDeoptimizationEntry) {
292
          id = Deoptimizer::GetDeoptimizationId(isolate,
293
                                                addr,
294
                                                Deoptimizer::LAZY);
295
          if (id == Deoptimizer::kNotDeoptimizationEntry) {
296
            id = Deoptimizer::GetDeoptimizationId(isolate,
297
                                                  addr,
298
                                                  Deoptimizer::SOFT);
299
            if (id == Deoptimizer::kNotDeoptimizationEntry) {
300
              out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
301
            } else {
302
              out.AddFormatted("    ;; soft deoptimization bailout %d", id);
303
            }
304
          } else {
305
            out.AddFormatted("    ;; lazy deoptimization bailout %d", id);
306
          }
307
        } else {
308
          out.AddFormatted("    ;; deoptimization bailout %d", id);
309
        }
310
      } else {
311
        out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
312
      }
313
    }
314
    DumpBuffer(f, &out);
315
  }
316

    
317
  // Emit comments following the last instruction (if any).
318
  if (it != NULL) {
319
    for ( ; !it->done(); it->next()) {
320
      if (RelocInfo::IsComment(it->rinfo()->rmode())) {
321
        out.AddFormatted("                  %s",
322
                         reinterpret_cast<const char*>(it->rinfo()->data()));
323
        DumpBuffer(f, &out);
324
      }
325
    }
326
  }
327

    
328
  delete it;
329
  return static_cast<int>(pc - begin);
330
}
331

    
332

    
333
int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
334
  V8NameConverter defaultConverter(NULL);
335
  return DecodeIt(isolate, f, defaultConverter, begin, end);
336
}
337

    
338

    
339
// Called by Code::CodePrint.
340
void Disassembler::Decode(FILE* f, Code* code) {
341
  Isolate* isolate = code->GetIsolate();
342
  int decode_size = code->is_crankshafted()
343
      ? static_cast<int>(code->safepoint_table_offset())
344
      : code->instruction_size();
345
  // If there might be a back edge table, stop before reaching it.
346
  if (code->kind() == Code::FUNCTION) {
347
    decode_size =
348
        Min(decode_size, static_cast<int>(code->back_edge_table_offset()));
349
  }
350

    
351
  byte* begin = code->instruction_start();
352
  byte* end = begin + decode_size;
353
  V8NameConverter v8NameConverter(code);
354
  DecodeIt(isolate, f, v8NameConverter, begin, end);
355
}
356

    
357
#else  // ENABLE_DISASSEMBLER
358

    
359
void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
360
int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
361
  return 0;
362
}
363

    
364

    
365
void Disassembler::Decode(FILE* f, Code* code) {}
366

    
367
#endif  // ENABLE_DISASSEMBLER
368

    
369
} }  // namespace v8::internal