github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-dump.c (about) 1 /* 2 * jit-dump.c - Functions for dumping JIT structures, for debugging. 3 * 4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd. 5 * 6 * This file is part of the libjit library. 7 * 8 * The libjit library is free software: you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation, either version 2.1 of 11 * the License, or (at your option) any later version. 12 * 13 * The libjit library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with the libjit library. If not, see 20 * <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "jit-internal.h" 24 #include "jit-rules.h" 25 #include <jit/jit-dump.h> 26 #ifdef HAVE_STDLIB_H 27 # include <stdlib.h> 28 #endif 29 #ifdef HAVE_UNISTD_H 30 # include <unistd.h> 31 #endif 32 33 #if defined(JIT_BACKEND_INTERP) 34 # include "jit-interp.h" 35 #endif 36 37 /*@ 38 39 @cindex jit-dump.h 40 41 The library provides some functions for dumping various objects to a 42 stream. These functions are declared in the header 43 @code{<jit/jit-dump.h>}. 44 45 @*/ 46 47 /*@ 48 * @deftypefun void jit_dump_type (FILE *@var{stream}, jit_type_t @var{type}) 49 * Dump the name of a type to a stdio stream. 50 * @end deftypefun 51 @*/ 52 void jit_dump_type(FILE *stream, jit_type_t type) 53 { 54 const char *name; 55 type = jit_type_remove_tags(type); 56 if(!type || !stream) 57 { 58 return; 59 } 60 switch(type->kind) 61 { 62 case JIT_TYPE_VOID: name = "void"; break; 63 case JIT_TYPE_SBYTE: name = "sbyte"; break; 64 case JIT_TYPE_UBYTE: name = "ubyte"; break; 65 case JIT_TYPE_SHORT: name = "short"; break; 66 case JIT_TYPE_USHORT: name = "ushort"; break; 67 case JIT_TYPE_INT: name = "int"; break; 68 case JIT_TYPE_UINT: name = "uint"; break; 69 case JIT_TYPE_NINT: name = "nint"; break; 70 case JIT_TYPE_NUINT: name = "nuint"; break; 71 case JIT_TYPE_LONG: name = "long"; break; 72 case JIT_TYPE_ULONG: name = "ulong"; break; 73 case JIT_TYPE_FLOAT32: name = "float32"; break; 74 case JIT_TYPE_FLOAT64: name = "float64"; break; 75 case JIT_TYPE_NFLOAT: name = "nfloat"; break; 76 77 case JIT_TYPE_STRUCT: 78 { 79 fprintf(stream, "struct<%u>", 80 (unsigned int)(jit_type_get_size(type))); 81 return; 82 } 83 /* Not reached */ 84 85 case JIT_TYPE_UNION: 86 { 87 fprintf(stream, "union<%u>", 88 (unsigned int)(jit_type_get_size(type))); 89 return; 90 } 91 /* Not reached */ 92 93 case JIT_TYPE_SIGNATURE: name = "signature"; break; 94 case JIT_TYPE_PTR: name = "ptr"; break; 95 default: name = "<unknown-type>"; break; 96 } 97 fputs(name, stream); 98 } 99 100 /* 101 * Format an integer value of arbitrary precision. 102 */ 103 static char *format_integer(char *buf, int is_neg, jit_ulong value) 104 { 105 buf += 64; 106 *(--buf) = '\0'; 107 if(value == 0) 108 { 109 *(--buf) = '0'; 110 } 111 else 112 { 113 while(value != 0) 114 { 115 *(--buf) = '0' + (int)(value % 10); 116 value /= 10; 117 } 118 } 119 if(is_neg) 120 { 121 *(--buf) = '-'; 122 } 123 return buf; 124 } 125 126 /*@ 127 * @deftypefun void jit_dump_value (FILE *@var{stream}, jit_function_t @var{func}, jit_value_t @var{value}, const char *@var{prefix}) 128 * Dump the name of a value to a stdio stream. If @var{prefix} is not 129 * NULL, then it indicates a type prefix to add to the value name. 130 * If @var{prefix} is NULL, then this function intuits the type prefix. 131 * @end deftypefun 132 @*/ 133 void jit_dump_value(FILE *stream, jit_function_t func, jit_value_t value, const char *prefix) 134 { 135 jit_pool_block_t block; 136 unsigned int block_size; 137 unsigned int posn; 138 139 /* Bail out if we have insufficient informaition for the dump */ 140 if(!stream || !func || !(func->builder) || !value) 141 { 142 return; 143 } 144 145 /* Handle constants and non-local variables */ 146 if(value->is_constant) 147 { 148 jit_constant_t const_value; 149 char buf[64]; 150 char *name; 151 const_value = jit_value_get_constant(value); 152 switch((jit_type_promote_int 153 (jit_type_normalize(const_value.type)))->kind) 154 { 155 case JIT_TYPE_INT: 156 { 157 if(const_value.un.int_value < 0) 158 { 159 name = format_integer 160 (buf, 1, (jit_ulong)(jit_uint) 161 (-(const_value.un.int_value))); 162 } 163 else 164 { 165 name = format_integer 166 (buf, 0, (jit_ulong)(jit_uint) 167 (const_value.un.int_value)); 168 } 169 } 170 break; 171 172 case JIT_TYPE_UINT: 173 { 174 name = format_integer 175 (buf, 0, (jit_ulong)(const_value.un.uint_value)); 176 } 177 break; 178 179 case JIT_TYPE_LONG: 180 { 181 if(const_value.un.long_value < 0) 182 { 183 name = format_integer 184 (buf, 1, (jit_ulong)(-(const_value.un.long_value))); 185 } 186 else 187 { 188 name = format_integer 189 (buf, 0, (jit_ulong)(const_value.un.long_value)); 190 } 191 } 192 break; 193 194 case JIT_TYPE_ULONG: 195 { 196 name = format_integer(buf, 0, const_value.un.ulong_value); 197 } 198 break; 199 200 case JIT_TYPE_FLOAT32: 201 { 202 jit_snprintf(buf, sizeof(buf), "%f", 203 (double)(const_value.un.float32_value)); 204 name = buf; 205 } 206 break; 207 208 case JIT_TYPE_FLOAT64: 209 { 210 jit_snprintf(buf, sizeof(buf), "%f", 211 (double)(const_value.un.float64_value)); 212 name = buf; 213 } 214 break; 215 216 case JIT_TYPE_NFLOAT: 217 { 218 jit_snprintf(buf, sizeof(buf), "%f", 219 (double)(const_value.un.nfloat_value)); 220 name = buf; 221 } 222 break; 223 224 default: 225 { 226 name = "<unknown-constant>"; 227 } 228 break; 229 } 230 fputs(name, stream); 231 return; 232 } 233 else if(value->is_local && value->block->func != func) 234 { 235 /* Accessing a local variable in an outer function frame */ 236 int scope = 0; 237 while(func && func->builder && func != value->block->func) 238 { 239 ++scope; 240 func = func->nested_parent; 241 } 242 fprintf(stream, "{%d}", scope); 243 if(!func || !(func->builder)) 244 { 245 return; 246 } 247 } 248 249 /* Intuit the prefix if one was not supplied */ 250 if(!prefix) 251 { 252 switch(jit_type_normalize(jit_value_get_type(value))->kind) 253 { 254 case JIT_TYPE_VOID: prefix = "v"; break; 255 case JIT_TYPE_SBYTE: prefix = "i"; break; 256 case JIT_TYPE_UBYTE: prefix = "i"; break; 257 case JIT_TYPE_SHORT: prefix = "i"; break; 258 case JIT_TYPE_USHORT: prefix = "i"; break; 259 case JIT_TYPE_INT: prefix = "i"; break; 260 case JIT_TYPE_UINT: prefix = "i"; break; 261 case JIT_TYPE_LONG: prefix = "l"; break; 262 case JIT_TYPE_ULONG: prefix = "l"; break; 263 case JIT_TYPE_FLOAT32: prefix = "f"; break; 264 case JIT_TYPE_FLOAT64: prefix = "d"; break; 265 case JIT_TYPE_NFLOAT: prefix = "D"; break; 266 case JIT_TYPE_STRUCT: prefix = "s"; break; 267 case JIT_TYPE_UNION: prefix = "u"; break; 268 default: prefix = "?"; break; 269 } 270 } 271 272 /* Get the position of the value within the function's value pool */ 273 block = func->builder->value_pool.blocks; 274 block_size = func->builder->value_pool.elem_size * 275 func->builder->value_pool.elems_per_block; 276 posn = 1; 277 while(block != 0) 278 { 279 if(((char *)value) >= block->data && 280 ((char *)value) < (block->data + block_size)) 281 { 282 posn += (((char *)value) - block->data) / 283 func->builder->value_pool.elem_size; 284 break; 285 } 286 posn += func->builder->value_pool.elems_per_block; 287 block = block->next; 288 } 289 290 /* Dump the prefix and the position, as the value's final name */ 291 fprintf(stream, "%s%u", prefix, posn); 292 } 293 294 /* 295 * Dump a temporary value, prefixed by its type. 296 */ 297 static void dump_value(FILE *stream, jit_function_t func, 298 jit_value_t value, int type) 299 { 300 /* Normalize the type, so that it reflects JIT_OPCODE_DEST_xxx values */ 301 if((type & JIT_OPCODE_SRC1_MASK) != 0) 302 { 303 type >>= 4; 304 } 305 if((type & JIT_OPCODE_SRC2_MASK) != 0) 306 { 307 type >>= 8; 308 } 309 310 /* Dump the value, prefixed appropriately */ 311 switch(type) 312 { 313 case JIT_OPCODE_DEST_INT: 314 { 315 jit_dump_value(stream, func, value, "i"); 316 } 317 break; 318 319 case JIT_OPCODE_DEST_LONG: 320 { 321 jit_dump_value(stream, func, value, "l"); 322 } 323 break; 324 325 case JIT_OPCODE_DEST_FLOAT32: 326 { 327 jit_dump_value(stream, func, value, "f"); 328 } 329 break; 330 331 case JIT_OPCODE_DEST_FLOAT64: 332 { 333 jit_dump_value(stream, func, value, "d"); 334 } 335 break; 336 337 case JIT_OPCODE_DEST_NFLOAT: 338 { 339 jit_dump_value(stream, func, value, "D"); 340 } 341 break; 342 343 case JIT_OPCODE_DEST_ANY: 344 { 345 /* Intuit the prefix from the value if the type is "any" */ 346 jit_dump_value(stream, func, value, 0); 347 } 348 break; 349 } 350 } 351 352 /*@ 353 * @deftypefun void jit_dump_insn (FILE *@var{stream}, jit_function_t @var{func}, jit_insn_t @var{insn}) 354 * Dump the contents of an instruction to a stdio stream. 355 * @end deftypefun 356 @*/ 357 void jit_dump_insn(FILE *stream, jit_function_t func, jit_insn_t insn) 358 { 359 const char *name; 360 const char *infix_name; 361 int opcode, flags; 362 jit_nint reg; 363 364 /* Bail out if we have insufficient information for the dump */ 365 if(!stream || !func || !insn) 366 { 367 return; 368 } 369 370 /* Get the opcode details */ 371 opcode = insn->opcode; 372 if(opcode < JIT_OP_NOP || opcode >= JIT_OP_NUM_OPCODES) 373 { 374 fprintf(stream, "unknown opcode %d\n", opcode); 375 return; 376 } 377 name = jit_opcodes[opcode].name; 378 flags = jit_opcodes[opcode].flags; 379 infix_name = 0; 380 381 /* Dump branch, call, or register information */ 382 if((flags & JIT_OPCODE_IS_BRANCH) != 0) 383 { 384 if(opcode == JIT_OP_BR) 385 { 386 fprintf(stream, "goto .L%ld", (long)(jit_insn_get_label(insn))); 387 return; 388 } 389 if(opcode == JIT_OP_CALL_FINALLY || opcode == JIT_OP_CALL_FILTER) 390 { 391 fprintf(stream, "%s .L%ld", name, (long)(jit_insn_get_label(insn))); 392 return; 393 } 394 fprintf(stream, "if "); 395 } 396 else if((flags & JIT_OPCODE_IS_CALL) != 0) 397 { 398 if(insn->value1) 399 fprintf(stream, "%s %s", name, (const char *)(insn->value1)); 400 else 401 fprintf(stream, "%s 0x08%lx", name, (long)(jit_nuint)(insn->dest)); 402 return; 403 } 404 else if((flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0) 405 { 406 if(insn->value1) 407 fprintf(stream, "%s %s (0x%08lx)", name, 408 (const char *)(insn->value1), 409 (long)(jit_nuint)(insn->dest)); 410 else 411 fprintf(stream, "%s 0x08%lx", name, 412 (long)(jit_nuint)(insn->dest)); 413 return; 414 } 415 else if((flags & JIT_OPCODE_IS_REG) != 0) 416 { 417 reg = jit_value_get_nint_constant(jit_insn_get_value2(insn)); 418 fputs(name, stream); 419 putc('(', stream); 420 jit_dump_value(stream, func, jit_insn_get_value1(insn), 0); 421 fputs(", ", stream); 422 fputs(jit_reg_name(reg), stream); 423 putc(')', stream); 424 return; 425 } 426 else if((flags & JIT_OPCODE_IS_ADDROF_LABEL) != 0) 427 { 428 dump_value(stream, func, jit_insn_get_dest(insn), flags & JIT_OPCODE_DEST_MASK); 429 fprintf(stream, " = "); 430 fprintf(stream, "address_of_label .L%ld", 431 (long)(jit_insn_get_label(insn))); 432 return; 433 } 434 else if((flags & JIT_OPCODE_IS_JUMP_TABLE) != 0) 435 { 436 jit_label_t *labels; 437 jit_nint num_labels, label; 438 labels = (jit_label_t *)jit_value_get_nint_constant(jit_insn_get_value1(insn)); 439 num_labels = jit_value_get_nint_constant(jit_insn_get_value2(insn)); 440 fprintf(stream, "%s ", name); 441 dump_value(stream, func, jit_insn_get_dest(insn), flags & JIT_OPCODE_DEST_MASK); 442 printf(" : {"); 443 for(label = 0; label < num_labels; label++) 444 { 445 printf(" .L%ld", (long) labels[label]); 446 } 447 printf(" }"); 448 return; 449 } 450 451 /* Output the destination information */ 452 if((flags & JIT_OPCODE_DEST_MASK) != JIT_OPCODE_DEST_EMPTY && 453 !jit_insn_dest_is_value(insn)) 454 { 455 dump_value(stream, func, jit_insn_get_dest(insn), 456 flags & JIT_OPCODE_DEST_MASK); 457 fprintf(stream, " = "); 458 } 459 460 /* Dump the details of the operation */ 461 switch(flags & JIT_OPCODE_OPER_MASK) 462 { 463 case JIT_OPCODE_OPER_ADD: infix_name = " + "; break; 464 case JIT_OPCODE_OPER_SUB: infix_name = " - "; break; 465 case JIT_OPCODE_OPER_MUL: infix_name = " * "; break; 466 case JIT_OPCODE_OPER_DIV: infix_name = " / "; break; 467 case JIT_OPCODE_OPER_REM: infix_name = " % "; break; 468 case JIT_OPCODE_OPER_NEG: infix_name = "-"; break; 469 case JIT_OPCODE_OPER_AND: infix_name = " & "; break; 470 case JIT_OPCODE_OPER_OR: infix_name = " | "; break; 471 case JIT_OPCODE_OPER_XOR: infix_name = " ^ "; break; 472 case JIT_OPCODE_OPER_NOT: infix_name = "~"; break; 473 case JIT_OPCODE_OPER_EQ: infix_name = " == "; break; 474 case JIT_OPCODE_OPER_NE: infix_name = " != "; break; 475 case JIT_OPCODE_OPER_LT: infix_name = " < "; break; 476 case JIT_OPCODE_OPER_LE: infix_name = " <= "; break; 477 case JIT_OPCODE_OPER_GT: infix_name = " > "; break; 478 case JIT_OPCODE_OPER_GE: infix_name = " >= "; break; 479 case JIT_OPCODE_OPER_SHL: infix_name = " << "; break; 480 case JIT_OPCODE_OPER_SHR: infix_name = " >> "; break; 481 case JIT_OPCODE_OPER_SHR_UN: infix_name = " >>> "; break; 482 case JIT_OPCODE_OPER_COPY: infix_name = ""; break; 483 case JIT_OPCODE_OPER_ADDRESS_OF: infix_name = "&"; break; 484 } 485 if(infix_name) 486 { 487 if((flags & JIT_OPCODE_SRC2_MASK) != 0) 488 { 489 /* Binary operation with a special operator name */ 490 dump_value(stream, func, jit_insn_get_value1(insn), 491 flags & JIT_OPCODE_SRC1_MASK); 492 fputs(infix_name, stream); 493 dump_value(stream, func, jit_insn_get_value2(insn), 494 flags & JIT_OPCODE_SRC2_MASK); 495 } 496 else 497 { 498 /* Unary operation with a special operator name */ 499 fputs(infix_name, stream); 500 dump_value(stream, func, jit_insn_get_value1(insn), 501 flags & JIT_OPCODE_SRC1_MASK); 502 } 503 } 504 else 505 { 506 /* Not a special operator, so use the opcode name */ 507 if(!jit_strncmp(name, "br_", 3)) 508 { 509 name += 3; 510 } 511 fputs(name, stream); 512 if((flags & (JIT_OPCODE_SRC1_MASK | JIT_OPCODE_SRC2_MASK)) != 0) 513 { 514 putc('(', stream); 515 if(jit_insn_dest_is_value(insn)) 516 { 517 dump_value(stream, func, jit_insn_get_dest(insn), 518 flags & JIT_OPCODE_DEST_MASK); 519 fputs(", ", stream); 520 } 521 dump_value(stream, func, jit_insn_get_value1(insn), 522 flags & JIT_OPCODE_SRC1_MASK); 523 if((flags & JIT_OPCODE_SRC2_MASK) != 0) 524 { 525 fputs(", ", stream); 526 dump_value(stream, func, jit_insn_get_value2(insn), 527 flags & JIT_OPCODE_SRC2_MASK); 528 } 529 putc(')', stream); 530 } 531 } 532 533 /* Dump the "then" information on a conditional branch */ 534 if((flags & JIT_OPCODE_IS_BRANCH) != 0) 535 { 536 fprintf(stream, " then goto .L%ld", (long)(jit_insn_get_label(insn))); 537 } 538 } 539 540 #if defined(JIT_BACKEND_INTERP) 541 542 /* 543 * Dump the interpreted bytecode representation of a function. 544 */ 545 static void dump_interp_code(FILE *stream, void **pc, void **end) 546 { 547 int opcode; 548 const jit_opcode_info_t *info; 549 while(pc < end) 550 { 551 /* Fetch the next opcode */ 552 opcode = (int)(jit_nint)(*pc); 553 554 /* Dump the address of the opcode */ 555 fprintf(stream, "\t%08lX: ", (long)(jit_nint)pc); 556 ++pc; 557 558 /* Get information about this opcode */ 559 if(opcode < JIT_OP_NUM_OPCODES) 560 { 561 info = &(jit_opcodes[opcode]); 562 } 563 else 564 { 565 info = &(_jit_interp_opcodes[opcode - JIT_OP_NUM_OPCODES]); 566 } 567 568 /* Dump the name of the opcode */ 569 fputs(info->name, stream); 570 571 /* Dump additional parameters from the opcode stream */ 572 switch(info->flags & JIT_OPCODE_INTERP_ARGS_MASK) 573 { 574 case JIT_OPCODE_NINT_ARG: 575 { 576 fprintf(stream, " %ld", (long)(jit_nint)(*pc)); 577 ++pc; 578 } 579 break; 580 581 case JIT_OPCODE_NINT_ARG_TWO: 582 { 583 fprintf(stream, " %ld, %ld", 584 (long)(jit_nint)(pc[0]), (long)(jit_nint)(pc[1])); 585 pc += 2; 586 } 587 break; 588 589 case JIT_OPCODE_CONST_LONG: 590 { 591 jit_ulong value; 592 jit_memcpy(&value, pc, sizeof(jit_ulong)); 593 pc += (sizeof(jit_ulong) + sizeof(void *) - 1) / 594 sizeof(void *); 595 fprintf(stream, " 0x%lX%08lX", 596 (long)((value >> 32) & jit_max_uint), 597 (long)(value & jit_max_uint)); 598 } 599 break; 600 601 case JIT_OPCODE_CONST_FLOAT32: 602 { 603 jit_float32 value; 604 jit_memcpy(&value, pc, sizeof(jit_float32)); 605 pc += (sizeof(jit_float32) + sizeof(void *) - 1) / 606 sizeof(void *); 607 fprintf(stream, " %f", (double)value); 608 } 609 break; 610 611 case JIT_OPCODE_CONST_FLOAT64: 612 { 613 jit_float64 value; 614 jit_memcpy(&value, pc, sizeof(jit_float64)); 615 pc += (sizeof(jit_float64) + sizeof(void *) - 1) / 616 sizeof(void *); 617 fprintf(stream, " %f", (double)value); 618 } 619 break; 620 621 case JIT_OPCODE_CONST_NFLOAT: 622 { 623 jit_nfloat value; 624 jit_memcpy(&value, pc, sizeof(jit_nfloat)); 625 pc += (sizeof(jit_nfloat) + sizeof(void *) - 1) / 626 sizeof(void *); 627 fprintf(stream, " %f", (double)value); 628 } 629 break; 630 631 case JIT_OPCODE_CALL_INDIRECT_ARGS: 632 { 633 fprintf(stream, " %ld", (long)(jit_nint)(pc[1])); 634 pc += 2; 635 } 636 break; 637 638 default: 639 { 640 if((info->flags & (JIT_OPCODE_IS_BRANCH | 641 JIT_OPCODE_IS_ADDROF_LABEL)) != 0) 642 { 643 fprintf(stream, " %08lX", 644 (long)(jit_nint)((pc - 1) + (jit_nint)(*pc))); 645 ++pc; 646 } 647 else if((info->flags & JIT_OPCODE_IS_CALL) != 0) 648 { 649 fprintf(stream, " 0x%lX", (long)(jit_nint)(*pc)); 650 ++pc; 651 } 652 else if((info->flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0) 653 { 654 fprintf(stream, " 0x%lX, %ld", 655 (long)(jit_nint)(pc[1]), (long)(jit_nint)(pc[2])); 656 pc += 3; 657 } 658 else if((info->flags & JIT_OPCODE_IS_JUMP_TABLE) != 0) 659 { 660 jit_nint label, num_labels; 661 num_labels = (jit_nint)pc[0]; 662 for(label = 1; label <= num_labels; label++) 663 { 664 fprintf(stream, " %lX", 665 (long)(jit_nint)pc[label]); 666 } 667 pc += 1 + num_labels; 668 } 669 } 670 break; 671 } 672 673 /* Terminate the current disassembly line */ 674 putc('\n', stream); 675 } 676 } 677 678 #else /* !JIT_BACKEND_INTERP */ 679 680 /* 681 * Dump the native object code representation of a function to stream. 682 */ 683 static void dump_object_code(FILE *stream, void *start, void *end) 684 { 685 char cmdline[BUFSIZ]; 686 unsigned char *pc = (unsigned char *)start; 687 FILE *file; 688 int ch; 689 690 #if JIT_WIN32_PLATFORM 691 char s_path[BUFSIZ]; 692 char o_path[BUFSIZ]; 693 char *tmp_dir = getenv("TMP"); 694 if(tmp_dir == NULL) 695 { 696 tmp_dir = getenv("TEMP"); 697 if(tmp_dir == NULL) 698 { 699 tmp_dir = "c:/tmp"; 700 } 701 } 702 sprintf(s_path, "%s/libjit-dump.s", tmp_dir); 703 sprintf(o_path, "%s/libjit-dump.o", tmp_dir); 704 #else 705 const char *s_path = "/tmp/libjit-dump.s"; 706 const char *o_path = "/tmp/libjit-dump.o"; 707 #endif 708 709 file = fopen(s_path, "w"); 710 if(!file) 711 { 712 return; 713 } 714 fflush(stream); 715 while(pc < (unsigned char *)end) 716 { 717 fprintf(file, ".byte %d\n", (int)(*pc)); 718 ++pc; 719 } 720 fclose(file); 721 sprintf(cmdline, "as %s -o %s", s_path, o_path); 722 system(cmdline); 723 sprintf(cmdline, "objdump --adjust-vma=%ld -d %s > %s", 724 (long)(jit_nint)start, o_path, s_path); 725 system(cmdline); 726 file = fopen(s_path, "r"); 727 if(file) 728 { 729 while((ch = getc(file)) != EOF) 730 { 731 putc(ch, stream); 732 } 733 fclose(file); 734 } 735 unlink(s_path); 736 unlink(o_path); 737 putc('\n', stream); 738 fflush(stream); 739 } 740 741 #endif /* !JIT_BACKEND_INTERP */ 742 743 /*@ 744 * @deftypefun void jit_dump_function (FILE *@var{stream}, jit_function_t @var{func}, const char *@var{name}) 745 * Dump the three-address instructions within a function to a stream. 746 * The @var{name} is attached to the output as a friendly label, but 747 * has no other significance. 748 * 749 * If the function has not been compiled yet, then this will dump the 750 * three address instructions from the build process. Otherwise it will 751 * disassemble and dump the compiled native code. 752 * @end deftypefun 753 @*/ 754 void jit_dump_function(FILE *stream, jit_function_t func, const char *name) 755 { 756 jit_block_t block; 757 jit_insn_iter_t iter; 758 jit_insn_t insn; 759 jit_type_t signature; 760 unsigned int param; 761 unsigned int num_params; 762 jit_value_t value; 763 jit_label_t label; 764 765 /* Bail out if we don't have sufficient information to dump */ 766 if(!stream || !func) 767 { 768 return; 769 } 770 771 /* Output the function header */ 772 if(name) 773 fprintf(stream, "function %s(", name); 774 else 775 fprintf(stream, "function 0x%08lX(", (long)(jit_nuint)func); 776 signature = func->signature; 777 num_params = jit_type_num_params(signature); 778 if(func->builder) 779 { 780 value = jit_value_get_struct_pointer(func); 781 if(value || func->nested_parent) 782 { 783 /* We have extra hidden parameters */ 784 putc('[', stream); 785 if(value) 786 { 787 jit_dump_value(stream, func, value, 0); 788 fputs(" : struct_ptr", stream); 789 if(func->nested_parent) 790 { 791 fputs(", ", stream); 792 } 793 } 794 if(func->nested_parent) 795 { 796 jit_dump_value(stream, func, func->parent_frame, 0); 797 fputs(" : parent_frame", stream); 798 } 799 putc(']', stream); 800 if(num_params > 0) 801 { 802 fputs(", ", stream); 803 } 804 } 805 for(param = 0; param < num_params; ++param) 806 { 807 if(param != 0) 808 { 809 fputs(", ", stream); 810 } 811 value = jit_value_get_param(func, param); 812 if(value) 813 { 814 jit_dump_value(stream, func, value, 0); 815 } 816 else 817 { 818 fputs("???", stream); 819 } 820 fputs(" : ", stream); 821 jit_dump_type(stream, jit_type_get_param(signature, param)); 822 } 823 } 824 else 825 { 826 for(param = 0; param < num_params; ++param) 827 { 828 if(param != 0) 829 { 830 fputs(", ", stream); 831 } 832 jit_dump_type(stream, jit_type_get_param(signature, param)); 833 } 834 } 835 fprintf(stream, ") : "); 836 jit_dump_type(stream, jit_type_get_return(signature)); 837 putc('\n', stream); 838 839 /* Should we dump the three address code or the native code? */ 840 if(func->builder) 841 { 842 /* Output each of the three address blocks in turn */ 843 block = 0; 844 while((block = jit_block_next(func, block)) != 0) 845 { 846 /* Output the block's labels, if it has any */ 847 label = jit_block_get_label(block); 848 if(block->label != jit_label_undefined) 849 { 850 for(;;) 851 { 852 fprintf(stream, ".L%ld:", (long) label); 853 label = jit_block_get_next_label(block, label); 854 if(label == jit_label_undefined) 855 { 856 fprintf(stream, "\n"); 857 break; 858 } 859 fprintf(stream, " "); 860 } 861 } 862 else if (block != func->builder->entry_block 863 /*&& _jit_block_get_last(block) != 0*/) 864 { 865 /* A new block was started, but it doesn't have a label yet */ 866 fprintf(stream, ".L:\n"); 867 } 868 869 /* Dump the instructions in the block */ 870 jit_insn_iter_init(&iter, block); 871 while((insn = jit_insn_iter_next(&iter)) != 0) 872 { 873 putc('\t', stream); 874 jit_dump_insn(stream, func, insn); 875 putc('\n', stream); 876 } 877 if(block->ends_in_dead) 878 { 879 fputs("\tends_in_dead\n", stream); 880 } 881 } 882 } 883 else if(func->is_compiled) 884 { 885 void *start = func->entry_point; 886 void *info = _jit_memory_find_function_info(func->context, start); 887 void *end = _jit_memory_get_function_end(func->context, info); 888 #if defined(JIT_BACKEND_INTERP) 889 /* Dump the interpreter's bytecode representation */ 890 jit_function_interp_t interp; 891 interp = (jit_function_interp_t)(func->entry_point); 892 fprintf(stream, "\t%08lX: prolog(0x%lX, %d, %d, %d)\n", 893 (long)(jit_nint)interp, (long)(jit_nint)func, 894 (int)(interp->args_size), (int)(interp->frame_size), 895 (int)(interp->working_area)); 896 dump_interp_code(stream, (void **)(interp + 1), (void **)end); 897 #else 898 dump_object_code(stream, start, end); 899 #endif 900 } 901 902 /* Output the function footer */ 903 fprintf(stream, "end\n\n"); 904 fflush(stream); 905 }