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.
main_repo / deps / v8 / src / disassembler.cc @ 40c0f755
History | View | Annotate | Download (10.8 KB)
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 { namespace internal { |
40 |
|
41 |
#ifdef ENABLE_DISASSEMBLER
|
42 |
|
43 |
void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
|
44 |
for (byte* pc = begin; pc < end; pc++) {
|
45 |
if (f == NULL) { |
46 |
PrintF("%p %4d %02x\n", pc, pc - begin, *pc);
|
47 |
} else {
|
48 |
fprintf(f, "%p %4d %02x\n", pc, pc - begin, *pc);
|
49 |
} |
50 |
} |
51 |
} |
52 |
|
53 |
|
54 |
class V8NameConverter: public disasm::NameConverter { |
55 |
public:
|
56 |
explicit V8NameConverter(Code* code) : code_(code) {}
|
57 |
virtual const char* NameOfAddress(byte* pc) const; |
58 |
virtual const char* NameInCode(byte* addr) const; |
59 |
Code* code() const { return code_; } |
60 |
private:
|
61 |
Code* code_; |
62 |
}; |
63 |
|
64 |
|
65 |
const char* V8NameConverter::NameOfAddress(byte* pc) const { |
66 |
static v8::internal::EmbeddedVector<char, 128> buffer; |
67 |
|
68 |
const char* name = Builtins::Lookup(pc); |
69 |
if (name != NULL) { |
70 |
OS::SNPrintF(buffer, "%s (%p)", name, pc);
|
71 |
return buffer.start();
|
72 |
} |
73 |
|
74 |
if (code_ != NULL) { |
75 |
int offs = pc - code_->instruction_start();
|
76 |
// print as code offset, if it seems reasonable
|
77 |
if (0 <= offs && offs < code_->instruction_size()) { |
78 |
OS::SNPrintF(buffer, "%d (%p)", offs, pc);
|
79 |
return buffer.start();
|
80 |
} |
81 |
} |
82 |
|
83 |
return disasm::NameConverter::NameOfAddress(pc);
|
84 |
} |
85 |
|
86 |
|
87 |
const char* V8NameConverter::NameInCode(byte* addr) const { |
88 |
// The V8NameConverter is used for well known code, so we can "safely"
|
89 |
// dereference pointers in generated code.
|
90 |
return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : ""; |
91 |
} |
92 |
|
93 |
|
94 |
static void DumpBuffer(FILE* f, char* buff) { |
95 |
if (f == NULL) { |
96 |
PrintF("%s", buff);
|
97 |
} else {
|
98 |
fprintf(f, "%s", buff);
|
99 |
} |
100 |
} |
101 |
|
102 |
static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength; |
103 |
static const int kRelocInfoPosition = 57; |
104 |
|
105 |
static int DecodeIt(FILE* f, |
106 |
const V8NameConverter& converter,
|
107 |
byte* begin, |
108 |
byte* end) { |
109 |
NoHandleAllocation ha; |
110 |
AssertNoAllocation no_alloc; |
111 |
ExternalReferenceEncoder ref_encoder; |
112 |
|
113 |
v8::internal::EmbeddedVector<char, 128> decode_buffer; |
114 |
v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
|
115 |
byte* pc = begin; |
116 |
disasm::Disassembler d(converter); |
117 |
RelocIterator* it = NULL;
|
118 |
if (converter.code() != NULL) { |
119 |
it = new RelocIterator(converter.code());
|
120 |
} else {
|
121 |
// No relocation information when printing code stubs.
|
122 |
} |
123 |
int constants = -1; // no constants being decoded at the start |
124 |
|
125 |
while (pc < end) {
|
126 |
// First decode instruction so that we know its length.
|
127 |
byte* prev_pc = pc; |
128 |
if (constants > 0) { |
129 |
OS::SNPrintF(decode_buffer, |
130 |
"%08x constant",
|
131 |
*reinterpret_cast<int32_t*>(pc));
|
132 |
constants--; |
133 |
pc += 4;
|
134 |
} else {
|
135 |
int num_const = d.ConstantPoolSizeAt(pc);
|
136 |
if (num_const >= 0) { |
137 |
OS::SNPrintF(decode_buffer, |
138 |
"%08x constant pool begin",
|
139 |
*reinterpret_cast<int32_t*>(pc));
|
140 |
constants = num_const; |
141 |
pc += 4;
|
142 |
} else if (it != NULL && !it->done() && it->rinfo()->pc() == pc && |
143 |
it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) { |
144 |
// raw pointer embedded in code stream, e.g., jump table
|
145 |
byte* ptr = *reinterpret_cast<byte**>(pc);
|
146 |
OS::SNPrintF(decode_buffer, |
147 |
"%08x jump table entry %4d",
|
148 |
reinterpret_cast<int32_t>(ptr),
|
149 |
ptr - begin); |
150 |
pc += 4;
|
151 |
} else {
|
152 |
decode_buffer[0] = '\0'; |
153 |
pc += d.InstructionDecode(decode_buffer, pc); |
154 |
} |
155 |
} |
156 |
|
157 |
// Collect RelocInfo for this instruction (prev_pc .. pc-1)
|
158 |
List<const char*> comments(4); |
159 |
List<byte*> pcs(1);
|
160 |
List<RelocInfo::Mode> rmodes(1);
|
161 |
List<intptr_t> datas(1);
|
162 |
if (it != NULL) { |
163 |
while (!it->done() && it->rinfo()->pc() < pc) {
|
164 |
if (RelocInfo::IsComment(it->rinfo()->rmode())) {
|
165 |
// For comments just collect the text.
|
166 |
comments.Add(reinterpret_cast<const char*>(it->rinfo()->data())); |
167 |
} else {
|
168 |
// For other reloc info collect all data.
|
169 |
pcs.Add(it->rinfo()->pc()); |
170 |
rmodes.Add(it->rinfo()->rmode()); |
171 |
datas.Add(it->rinfo()->data()); |
172 |
} |
173 |
it->next(); |
174 |
} |
175 |
} |
176 |
|
177 |
StringBuilder out(out_buffer.start(), out_buffer.length()); |
178 |
|
179 |
// Comments.
|
180 |
for (int i = 0; i < comments.length(); i++) { |
181 |
out.AddFormatted(" %s\n", comments[i]);
|
182 |
} |
183 |
|
184 |
// Write out comments, resets outp so that we can format the next line.
|
185 |
DumpBuffer(f, out.Finalize()); |
186 |
out.Reset(); |
187 |
|
188 |
// Instruction address and instruction offset.
|
189 |
out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin);
|
190 |
|
191 |
// Instruction.
|
192 |
out.AddFormatted("%s", decode_buffer.start());
|
193 |
|
194 |
// Print all the reloc info for this instruction which are not comments.
|
195 |
for (int i = 0; i < pcs.length(); i++) { |
196 |
// Put together the reloc info
|
197 |
RelocInfo relocinfo(pcs[i], rmodes[i], datas[i]); |
198 |
|
199 |
// Indent the printing of the reloc info.
|
200 |
if (i == 0) { |
201 |
// The first reloc info is printed after the disassembled instruction.
|
202 |
out.AddPadding(' ', kRelocInfoPosition - out.position());
|
203 |
} else {
|
204 |
// Additional reloc infos are printed on separate lines.
|
205 |
out.AddFormatted("\n");
|
206 |
out.AddPadding(' ', kRelocInfoPosition);
|
207 |
} |
208 |
|
209 |
RelocInfo::Mode rmode = relocinfo.rmode(); |
210 |
if (RelocInfo::IsPosition(rmode)) {
|
211 |
if (RelocInfo::IsStatementPosition(rmode)) {
|
212 |
out.AddFormatted(" ;; debug: statement %d", relocinfo.data());
|
213 |
} else {
|
214 |
out.AddFormatted(" ;; debug: position %d", relocinfo.data());
|
215 |
} |
216 |
} else if (rmode == RelocInfo::EMBEDDED_OBJECT) { |
217 |
HeapStringAllocator allocator; |
218 |
StringStream accumulator(&allocator); |
219 |
relocinfo.target_object()->ShortPrint(&accumulator); |
220 |
SmartPointer<const char> obj_name = accumulator.ToCString(); |
221 |
out.AddFormatted(" ;; object: %s", *obj_name);
|
222 |
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) { |
223 |
const char* reference_name = |
224 |
ref_encoder.NameOfAddress(*relocinfo.target_reference_address()); |
225 |
out.AddFormatted(" ;; external reference (%s)", reference_name);
|
226 |
} else if (RelocInfo::IsCodeTarget(rmode)) { |
227 |
out.AddFormatted(" ;; code:");
|
228 |
if (rmode == RelocInfo::CONSTRUCT_CALL) {
|
229 |
out.AddFormatted(" constructor,");
|
230 |
} |
231 |
Code* code = Code::GetCodeFromTargetAddress(relocinfo.target_address()); |
232 |
Code::Kind kind = code->kind(); |
233 |
if (code->is_inline_cache_stub()) {
|
234 |
if (rmode == RelocInfo::CODE_TARGET_CONTEXT) {
|
235 |
out.AddFormatted(" contextual,");
|
236 |
} |
237 |
InlineCacheState ic_state = code->ic_state(); |
238 |
out.AddFormatted(" %s, %s", Code::Kind2String(kind),
|
239 |
Code::ICState2String(ic_state)); |
240 |
if (kind == Code::CALL_IC) {
|
241 |
out.AddFormatted(", argc = %d", code->arguments_count());
|
242 |
} |
243 |
} else if (kind == Code::STUB) { |
244 |
// Reverse lookup required as the minor key cannot be retrieved
|
245 |
// from the code object.
|
246 |
Object* obj = Heap::code_stubs()->SlowReverseLookup(code); |
247 |
if (obj != Heap::undefined_value()) {
|
248 |
ASSERT(obj->IsSmi()); |
249 |
// Get the STUB key and extract major and minor key.
|
250 |
uint32_t key = Smi::cast(obj)->value(); |
251 |
uint32_t minor_key = CodeStub::MinorKeyFromKey(key); |
252 |
ASSERT(code->major_key() == CodeStub::MajorKeyFromKey(key)); |
253 |
out.AddFormatted(" %s, %s, ",
|
254 |
Code::Kind2String(kind), |
255 |
CodeStub::MajorName(code->major_key())); |
256 |
switch (code->major_key()) {
|
257 |
case CodeStub::CallFunction:
|
258 |
out.AddFormatted("argc = %d", minor_key);
|
259 |
break;
|
260 |
case CodeStub::Runtime: {
|
261 |
const char* name = |
262 |
RuntimeStub::GetNameFromMinorKey(minor_key); |
263 |
out.AddFormatted("%s", name);
|
264 |
break;
|
265 |
} |
266 |
default:
|
267 |
out.AddFormatted("minor: %d", minor_key);
|
268 |
} |
269 |
} |
270 |
} else {
|
271 |
out.AddFormatted(" %s", Code::Kind2String(kind));
|
272 |
} |
273 |
} else {
|
274 |
out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
|
275 |
} |
276 |
} |
277 |
out.AddString("\n");
|
278 |
DumpBuffer(f, out.Finalize()); |
279 |
out.Reset(); |
280 |
} |
281 |
|
282 |
delete it;
|
283 |
return pc - begin;
|
284 |
} |
285 |
|
286 |
|
287 |
int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
|
288 |
V8NameConverter defaultConverter(NULL);
|
289 |
return DecodeIt(f, defaultConverter, begin, end);
|
290 |
} |
291 |
|
292 |
|
293 |
// Called by Code::CodePrint.
|
294 |
void Disassembler::Decode(FILE* f, Code* code) {
|
295 |
byte* begin = Code::cast(code)->instruction_start(); |
296 |
byte* end = begin + Code::cast(code)->instruction_size(); |
297 |
V8NameConverter v8NameConverter(code); |
298 |
DecodeIt(f, v8NameConverter, begin, end); |
299 |
} |
300 |
|
301 |
#else // ENABLE_DISASSEMBLER |
302 |
|
303 |
void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
|
304 |
int Disassembler::Decode(FILE* f, byte* begin, byte* end) { return 0; } |
305 |
void Disassembler::Decode(FILE* f, Code* code) {}
|
306 |
|
307 |
#endif // ENABLE_DISASSEMBLER |
308 |
|
309 |
} } // namespace v8::internal
|