1// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if !defined(DART_PRECOMPILED_RUNTIME)
7
8#include "vm/compiler/assembler/disassembler_kbc.h"
9
10#include "platform/assert.h"
11#include "vm/compiler/frontend/bytecode_reader.h"
12#include "vm/constants_kbc.h"
13#include "vm/cpu.h"
14#include "vm/instructions.h"
15
16namespace dart {
17
18static const char* kOpcodeNames[] = {
19#define BYTECODE_NAME(name, encoding, kind, op1, op2, op3) #name,
20 KERNEL_BYTECODES_LIST(BYTECODE_NAME)
21#undef BYTECODE_NAME
22};
23
24static const size_t kOpcodeCount =
25 sizeof(kOpcodeNames) / sizeof(kOpcodeNames[0]);
26static_assert(kOpcodeCount <= 256, "Opcode should fit into a byte");
27
28typedef void (*BytecodeFormatter)(char* buffer,
29 intptr_t size,
30 KernelBytecode::Opcode opcode,
31 const KBCInstr* instr);
32typedef void (*Fmt)(char** buf,
33 intptr_t* size,
34 const KBCInstr* instr,
35 int32_t value);
36
37template <typename ValueType>
38void FormatOperand(char** buf,
39 intptr_t* size,
40 const char* fmt,
41 ValueType value) {
42 intptr_t written = Utils::SNPrint(*buf, *size, fmt, value);
43 if (written < *size) {
44 *buf += written;
45 *size += written;
46 } else {
47 *size = -1;
48 }
49}
50
51static void Fmt___(char** buf,
52 intptr_t* size,
53 const KBCInstr* instr,
54 int32_t value) {}
55
56static void Fmttgt(char** buf,
57 intptr_t* size,
58 const KBCInstr* instr,
59 int32_t value) {
60 if (FLAG_disassemble_relative) {
61 FormatOperand(buf, size, "-> %" Pd, value);
62 } else {
63 FormatOperand(buf, size, "-> %" Px, instr + value);
64 }
65}
66
67static void Fmtlit(char** buf,
68 intptr_t* size,
69 const KBCInstr* instr,
70 int32_t value) {
71 FormatOperand(buf, size, "k%d", value);
72}
73
74static void Fmtreg(char** buf,
75 intptr_t* size,
76 const KBCInstr* instr,
77 int32_t value) {
78 FormatOperand(buf, size, "r%d", value);
79}
80
81static void Fmtxeg(char** buf,
82 intptr_t* size,
83 const KBCInstr* instr,
84 int32_t value) {
85 if (value < 0) {
86 FormatOperand(buf, size, "FP[%d]", value);
87 } else {
88 Fmtreg(buf, size, instr, value);
89 }
90}
91
92static void Fmtnum(char** buf,
93 intptr_t* size,
94 const KBCInstr* instr,
95 int32_t value) {
96 FormatOperand(buf, size, "#%d", value);
97}
98
99static void Apply(char** buf,
100 intptr_t* size,
101 const KBCInstr* instr,
102 Fmt fmt,
103 int32_t value,
104 const char* suffix) {
105 if (*size <= 0) {
106 return;
107 }
108
109 fmt(buf, size, instr, value);
110 if (*size > 0) {
111 FormatOperand(buf, size, "%s", suffix);
112 }
113}
114
115static void Format0(char* buf,
116 intptr_t size,
117 KernelBytecode::Opcode opcode,
118 const KBCInstr* instr,
119 Fmt op1,
120 Fmt op2,
121 Fmt op3) {}
122
123static void FormatA(char* buf,
124 intptr_t size,
125 KernelBytecode::Opcode opcode,
126 const KBCInstr* instr,
127 Fmt op1,
128 Fmt op2,
129 Fmt op3) {
130 const int32_t a = KernelBytecode::DecodeA(instr);
131 Apply(&buf, &size, instr, op1, a, "");
132}
133
134static void FormatD(char* buf,
135 intptr_t size,
136 KernelBytecode::Opcode opcode,
137 const KBCInstr* instr,
138 Fmt op1,
139 Fmt op2,
140 Fmt op3) {
141 const int32_t bc = KernelBytecode::DecodeD(instr);
142 Apply(&buf, &size, instr, op1, bc, "");
143}
144
145static void FormatX(char* buf,
146 intptr_t size,
147 KernelBytecode::Opcode opcode,
148 const KBCInstr* instr,
149 Fmt op1,
150 Fmt op2,
151 Fmt op3) {
152 const int32_t bc = KernelBytecode::DecodeX(instr);
153 Apply(&buf, &size, instr, op1, bc, "");
154}
155
156static void FormatT(char* buf,
157 intptr_t size,
158 KernelBytecode::Opcode opcode,
159 const KBCInstr* instr,
160 Fmt op1,
161 Fmt op2,
162 Fmt op3) {
163 const int32_t x = KernelBytecode::DecodeT(instr);
164 Apply(&buf, &size, instr, op1, x, "");
165}
166
167static void FormatA_E(char* buf,
168 intptr_t size,
169 KernelBytecode::Opcode opcode,
170 const KBCInstr* instr,
171 Fmt op1,
172 Fmt op2,
173 Fmt op3) {
174 const int32_t a = KernelBytecode::DecodeA(instr);
175 const int32_t e = KernelBytecode::DecodeE(instr);
176 Apply(&buf, &size, instr, op1, a, ", ");
177 Apply(&buf, &size, instr, op2, e, "");
178}
179
180static void FormatA_Y(char* buf,
181 intptr_t size,
182 KernelBytecode::Opcode opcode,
183 const KBCInstr* instr,
184 Fmt op1,
185 Fmt op2,
186 Fmt op3) {
187 const int32_t a = KernelBytecode::DecodeA(instr);
188 const int32_t y = KernelBytecode::DecodeY(instr);
189 Apply(&buf, &size, instr, op1, a, ", ");
190 Apply(&buf, &size, instr, op2, y, "");
191}
192
193static void FormatD_F(char* buf,
194 intptr_t size,
195 KernelBytecode::Opcode opcode,
196 const KBCInstr* instr,
197 Fmt op1,
198 Fmt op2,
199 Fmt op3) {
200 const int32_t d = KernelBytecode::DecodeD(instr);
201 const int32_t f = KernelBytecode::DecodeF(instr);
202 Apply(&buf, &size, instr, op1, d, ", ");
203 Apply(&buf, &size, instr, op2, f, "");
204}
205
206static void FormatA_B_C(char* buf,
207 intptr_t size,
208 KernelBytecode::Opcode opcode,
209 const KBCInstr* instr,
210 Fmt op1,
211 Fmt op2,
212 Fmt op3) {
213 const int32_t a = KernelBytecode::DecodeA(instr);
214 const int32_t b = KernelBytecode::DecodeB(instr);
215 const int32_t c = KernelBytecode::DecodeC(instr);
216 Apply(&buf, &size, instr, op1, a, ", ");
217 Apply(&buf, &size, instr, op2, b, ", ");
218 Apply(&buf, &size, instr, op3, c, "");
219}
220
221#define BYTECODE_FORMATTER(name, encoding, kind, op1, op2, op3) \
222 static void Format##name(char* buf, intptr_t size, \
223 KernelBytecode::Opcode opcode, \
224 const KBCInstr* instr) { \
225 Format##encoding(buf, size, opcode, instr, Fmt##op1, Fmt##op2, Fmt##op3); \
226 }
227KERNEL_BYTECODES_LIST(BYTECODE_FORMATTER)
228#undef BYTECODE_FORMATTER
229
230static const BytecodeFormatter kFormatters[] = {
231#define BYTECODE_FORMATTER(name, encoding, kind, op1, op2, op3) &Format##name,
232 KERNEL_BYTECODES_LIST(BYTECODE_FORMATTER)
233#undef BYTECODE_FORMATTER
234};
235
236static intptr_t GetConstantPoolIndex(const KBCInstr* instr) {
237 switch (KernelBytecode::DecodeOpcode(instr)) {
238 case KernelBytecode::kLoadConstant:
239 case KernelBytecode::kLoadConstant_Wide:
240 case KernelBytecode::kInstantiateTypeArgumentsTOS:
241 case KernelBytecode::kInstantiateTypeArgumentsTOS_Wide:
242 case KernelBytecode::kAssertAssignable:
243 case KernelBytecode::kAssertAssignable_Wide:
244 return KernelBytecode::DecodeE(instr);
245
246 case KernelBytecode::kPushConstant:
247 case KernelBytecode::kPushConstant_Wide:
248 case KernelBytecode::kInitLateField:
249 case KernelBytecode::kInitLateField_Wide:
250 case KernelBytecode::kStoreStaticTOS:
251 case KernelBytecode::kStoreStaticTOS_Wide:
252 case KernelBytecode::kLoadStatic:
253 case KernelBytecode::kLoadStatic_Wide:
254 case KernelBytecode::kAllocate:
255 case KernelBytecode::kAllocate_Wide:
256 case KernelBytecode::kAllocateClosure:
257 case KernelBytecode::kAllocateClosure_Wide:
258 case KernelBytecode::kInstantiateType:
259 case KernelBytecode::kInstantiateType_Wide:
260 case KernelBytecode::kDirectCall:
261 case KernelBytecode::kDirectCall_Wide:
262 case KernelBytecode::kUncheckedDirectCall:
263 case KernelBytecode::kUncheckedDirectCall_Wide:
264 case KernelBytecode::kInterfaceCall:
265 case KernelBytecode::kInterfaceCall_Wide:
266 case KernelBytecode::kInstantiatedInterfaceCall:
267 case KernelBytecode::kInstantiatedInterfaceCall_Wide:
268 case KernelBytecode::kUncheckedClosureCall:
269 case KernelBytecode::kUncheckedClosureCall_Wide:
270 case KernelBytecode::kUncheckedInterfaceCall:
271 case KernelBytecode::kUncheckedInterfaceCall_Wide:
272 case KernelBytecode::kDynamicCall:
273 case KernelBytecode::kDynamicCall_Wide:
274 return KernelBytecode::DecodeD(instr);
275
276 default:
277 return -1;
278 }
279}
280
281static bool GetLoadedObjectAt(uword pc,
282 const ObjectPool& object_pool,
283 Object* obj) {
284 const KBCInstr* instr = reinterpret_cast<const KBCInstr*>(pc);
285 const intptr_t index = GetConstantPoolIndex(instr);
286 if (index >= 0) {
287 if (object_pool.TypeAt(index) == ObjectPool::EntryType::kTaggedObject) {
288 *obj = object_pool.ObjectAt(index);
289 return true;
290 }
291 }
292 return false;
293}
294
295void KernelBytecodeDisassembler::DecodeInstruction(char* hex_buffer,
296 intptr_t hex_size,
297 char* human_buffer,
298 intptr_t human_size,
299 int* out_instr_size,
300 const Bytecode& bytecode,
301 Object** object,
302 uword pc) {
303 const KBCInstr* instr = reinterpret_cast<const KBCInstr*>(pc);
304 const KernelBytecode::Opcode opcode = KernelBytecode::DecodeOpcode(instr);
305 const intptr_t instr_size = KernelBytecode::kInstructionSize[opcode];
306
307 size_t name_size =
308 Utils::SNPrint(human_buffer, human_size, "%-10s\t", kOpcodeNames[opcode]);
309 human_buffer += name_size;
310 human_size -= name_size;
311 kFormatters[opcode](human_buffer, human_size, opcode, instr);
312
313 const intptr_t kCharactersPerByte = 3;
314 if (hex_size > instr_size * kCharactersPerByte) {
315 for (intptr_t i = 0; i < instr_size; ++i) {
316 Utils::SNPrint(hex_buffer + (i * kCharactersPerByte),
317 hex_size - (i * kCharactersPerByte), " %02x", instr[i]);
318 }
319 }
320 if (out_instr_size != nullptr) {
321 *out_instr_size = instr_size;
322 }
323
324 *object = NULL;
325 if (!bytecode.IsNull()) {
326 *object = &Object::Handle();
327 const ObjectPool& pool = ObjectPool::Handle(bytecode.object_pool());
328 if (!GetLoadedObjectAt(pc, pool, *object)) {
329 *object = NULL;
330 }
331 }
332}
333
334void KernelBytecodeDisassembler::Disassemble(uword start,
335 uword end,
336 DisassemblyFormatter* formatter,
337 const Bytecode& bytecode) {
338#if !defined(PRODUCT)
339 ASSERT(formatter != NULL);
340 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form.
341 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction.
342 uword pc = start;
343 GrowableArray<const Function*> inlined_functions;
344 GrowableArray<TokenPosition> token_positions;
345 while (pc < end) {
346 int instruction_length;
347 Object* object;
348 DecodeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer,
349 sizeof(human_buffer), &instruction_length, bytecode,
350 &object, pc);
351 formatter->ConsumeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer,
352 sizeof(human_buffer), object,
353 FLAG_disassemble_relative ? pc - start : pc);
354 pc += instruction_length;
355 }
356#else
357 UNREACHABLE();
358#endif
359}
360
361void KernelBytecodeDisassembler::Disassemble(const Function& function) {
362#if !defined(PRODUCT)
363 ASSERT(function.HasBytecode());
364 const char* function_fullname = function.ToFullyQualifiedCString();
365 Zone* zone = Thread::Current()->zone();
366 const Bytecode& bytecode = Bytecode::Handle(zone, function.bytecode());
367 THR_Print("Bytecode for function '%s' {\n", function_fullname);
368 const uword start = bytecode.PayloadStart();
369 const uword base = FLAG_disassemble_relative ? 0 : start;
370 DisassembleToStdout stdout_formatter;
371 LogBlock lb;
372 Disassemble(start, start + bytecode.Size(), &stdout_formatter, bytecode);
373 THR_Print("}\n");
374
375 const ObjectPool& object_pool =
376 ObjectPool::Handle(zone, bytecode.object_pool());
377 object_pool.DebugPrint();
378
379 THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
380 PcDescriptors::PrintHeaderString();
381 const PcDescriptors& descriptors =
382 PcDescriptors::Handle(zone, bytecode.pc_descriptors());
383 THR_Print("%s}\n", descriptors.ToCString());
384
385 if (bytecode.HasSourcePositions()) {
386 THR_Print("Source positions for function '%s' {\n", function_fullname);
387 // 4 bits per hex digit + 2 for "0x".
388 const int addr_width = (kBitsPerWord / 4) + 2;
389 // "*" in a printf format specifier tells it to read the field width from
390 // the printf argument list.
391 THR_Print("%-*s\tpos\tline\tcolumn\tyield\n", addr_width, "pc");
392 const Script& script = Script::Handle(zone, function.script());
393 kernel::BytecodeSourcePositionsIterator iter(zone, bytecode);
394 while (iter.MoveNext()) {
395 TokenPosition pos = iter.TokenPos();
396 intptr_t line = -1, column = -1;
397 script.GetTokenLocation(pos, &line, &column);
398 THR_Print("%#-*" Px "\t%s\t%" Pd "\t%" Pd "\t%s\n", addr_width,
399 base + iter.PcOffset(), pos.ToCString(), line, column,
400 iter.IsYieldPoint() ? "yield" : "");
401 }
402 THR_Print("}\n");
403 }
404
405 if (FLAG_print_variable_descriptors && bytecode.HasLocalVariablesInfo()) {
406 THR_Print("Local variables info for function '%s' {\n", function_fullname);
407 kernel::BytecodeLocalVariablesIterator iter(zone, bytecode);
408 while (iter.MoveNext()) {
409 switch (iter.Kind()) {
410 case kernel::BytecodeLocalVariablesIterator::kScope: {
411 THR_Print("scope 0x%" Px "-0x%" Px " pos %s-%s\tlev %" Pd "\n",
412 base + iter.StartPC(), base + iter.EndPC(),
413 iter.StartTokenPos().ToCString(),
414 iter.EndTokenPos().ToCString(), iter.ContextLevel());
415 } break;
416 case kernel::BytecodeLocalVariablesIterator::kVariableDeclaration: {
417 THR_Print("var 0x%" Px "-0x%" Px " pos %s-%s\tidx %" Pd
418 "\tdecl %s\t%s %s %s\n",
419 base + iter.StartPC(), base + iter.EndPC(),
420 iter.StartTokenPos().ToCString(),
421 iter.EndTokenPos().ToCString(), iter.Index(),
422 iter.DeclarationTokenPos().ToCString(),
423 String::Handle(
424 zone, AbstractType::Handle(zone, iter.Type()).Name())
425 .ToCString(),
426 String::Handle(zone, iter.Name()).ToCString(),
427 iter.IsCaptured() ? "captured" : "");
428 } break;
429 case kernel::BytecodeLocalVariablesIterator::kContextVariable: {
430 THR_Print("ctxt 0x%" Px "\tidx %" Pd "\n", base + iter.StartPC(),
431 iter.Index());
432 } break;
433 }
434 }
435 THR_Print("}\n");
436
437 THR_Print("Local variable descriptors for function '%s' {\n",
438 function_fullname);
439 const auto& var_descriptors =
440 LocalVarDescriptors::Handle(zone, bytecode.GetLocalVarDescriptors());
441 THR_Print("%s}\n", var_descriptors.ToCString());
442 }
443
444 THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
445 const ExceptionHandlers& handlers =
446 ExceptionHandlers::Handle(zone, bytecode.exception_handlers());
447 THR_Print("%s}\n", handlers.ToCString());
448
449#else
450 UNREACHABLE();
451#endif
452}
453
454} // namespace dart
455
456#endif // !defined(DART_PRECOMPILED_RUNTIME)
457