diff options
| author | Paul Eggert | 2016-12-23 21:13:58 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-12-23 21:46:53 -0800 |
| commit | a815e5f19581344af5e143636039064a7fbe83ed (patch) | |
| tree | f5ed9c34657f1a86d85020d30826d07d9fa4d56b /src/bytecode.c | |
| parent | a43cfb1ad55cad553d54798356c69e2496a3e504 (diff) | |
| download | emacs-a815e5f19581344af5e143636039064a7fbe83ed.tar.gz emacs-a815e5f19581344af5e143636039064a7fbe83ed.zip | |
Remove interpreter’s byte stack
This improves performance overall on my benchmark on x86-64,
since the interpreted program-counter resides in a machine
register rather than in RAM.
* etc/DEBUG, src/.gdbinit: Remove xbytecode GDB command, as there
is no longer a byte stack to decode.
* src/bytecode.c (struct byte_stack, byte_stack_list)
(relocate_byte_stack): Remove. All uses removed.
(FETCH): Simplify now that pc is now local (typically, in a
register) and no longer needs to be relocated.
(CHECK_RANGE): Remove. All uses now done inline, in a different way.
(BYTE_CODE_QUIT): Remove; now done by op_relative_branch.
(exec_byte_code): Allocate a copy of the function’s bytecode,
so that there is no problem if GC moves it.
* src/lisp.h (struct handler): Remove byte_stack member.
All uses removed.
* src/thread.c (unmark_threads): Remove. All uses removed.
* src/thread.h (struct thread_state): Remove m_byte_stack_list member.
All uses removed. m_stack_bottom is now the first non-Lisp field.
Diffstat (limited to 'src/bytecode.c')
| -rw-r--r-- | src/bytecode.c | 200 |
1 files changed, 55 insertions, 145 deletions
diff --git a/src/bytecode.c b/src/bytecode.c index 5e0055f4ee4..51546ca474d 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -281,58 +281,9 @@ enum byte_code_op | |||
| 281 | #endif | 281 | #endif |
| 282 | }; | 282 | }; |
| 283 | 283 | ||
| 284 | /* Structure describing a value stack used during byte-code execution | ||
| 285 | in Fbyte_code. */ | ||
| 286 | |||
| 287 | struct byte_stack | ||
| 288 | { | ||
| 289 | /* Program counter. This points into the byte_string below | ||
| 290 | and is relocated when that string is relocated. */ | ||
| 291 | const unsigned char *pc; | ||
| 292 | |||
| 293 | /* The string containing the byte-code, and its current address. | ||
| 294 | Storing this here protects it from GC because mark_byte_stack | ||
| 295 | marks it. */ | ||
| 296 | Lisp_Object byte_string; | ||
| 297 | const unsigned char *byte_string_start; | ||
| 298 | |||
| 299 | /* Next entry in byte_stack_list. */ | ||
| 300 | struct byte_stack *next; | ||
| 301 | }; | ||
| 302 | |||
| 303 | /* A list of currently active byte-code execution value stacks. | ||
| 304 | Fbyte_code adds an entry to the head of this list before it starts | ||
| 305 | processing byte-code, and it removes the entry again when it is | ||
| 306 | done. Signaling an error truncates the list. | ||
| 307 | |||
| 308 | byte_stack_list is a macro defined in thread.h. */ | ||
| 309 | /* struct byte_stack *byte_stack_list; */ | ||
| 310 | |||
| 311 | |||
| 312 | /* Relocate program counters in the stacks on byte_stack_list. Called | ||
| 313 | when GC has completed. */ | ||
| 314 | |||
| 315 | void | ||
| 316 | relocate_byte_stack (struct byte_stack *stack) | ||
| 317 | { | ||
| 318 | for (; stack; stack = stack->next) | ||
| 319 | { | ||
| 320 | if (stack->byte_string_start != SDATA (stack->byte_string)) | ||
| 321 | { | ||
| 322 | ptrdiff_t offset = stack->pc - stack->byte_string_start; | ||
| 323 | stack->byte_string_start = SDATA (stack->byte_string); | ||
| 324 | stack->pc = stack->byte_string_start + offset; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 330 | /* Fetch the next byte from the bytecode stream. */ | 284 | /* Fetch the next byte from the bytecode stream. */ |
| 331 | #if BYTE_CODE_SAFE | 285 | |
| 332 | #define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)), *stack.pc++) | 286 | #define FETCH (*pc++) |
| 333 | #else | ||
| 334 | #define FETCH *stack.pc++ | ||
| 335 | #endif | ||
| 336 | 287 | ||
| 337 | /* Fetch two bytes from the bytecode stream and make a 16-bit number | 288 | /* Fetch two bytes from the bytecode stream and make a 16-bit number |
| 338 | out of them. */ | 289 | out of them. */ |
| @@ -357,29 +308,6 @@ relocate_byte_stack (struct byte_stack *stack) | |||
| 357 | 308 | ||
| 358 | #define TOP (*top) | 309 | #define TOP (*top) |
| 359 | 310 | ||
| 360 | #define CHECK_RANGE(ARG) \ | ||
| 361 | (BYTE_CODE_SAFE && bytestr_length <= (ARG) ? emacs_abort () : (void) 0) | ||
| 362 | |||
| 363 | /* A version of the QUIT macro which makes sure that the stack top is | ||
| 364 | set before signaling `quit'. */ | ||
| 365 | #define BYTE_CODE_QUIT \ | ||
| 366 | do { \ | ||
| 367 | if (quitcounter++) \ | ||
| 368 | break; \ | ||
| 369 | maybe_gc (); \ | ||
| 370 | if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \ | ||
| 371 | { \ | ||
| 372 | Lisp_Object flag = Vquit_flag; \ | ||
| 373 | Vquit_flag = Qnil; \ | ||
| 374 | if (EQ (Vthrow_on_input, flag)) \ | ||
| 375 | Fthrow (Vthrow_on_input, Qt); \ | ||
| 376 | quit (); \ | ||
| 377 | } \ | ||
| 378 | else if (pending_signals) \ | ||
| 379 | process_pending_signals (); \ | ||
| 380 | } while (0) | ||
| 381 | |||
| 382 | |||
| 383 | DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, | 311 | DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, |
| 384 | doc: /* Function used internally in byte-compiled code. | 312 | doc: /* Function used internally in byte-compiled code. |
| 385 | The first argument, BYTESTR, is a string of byte code; | 313 | The first argument, BYTESTR, is a string of byte code; |
| @@ -429,19 +357,18 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 429 | 357 | ||
| 430 | ptrdiff_t bytestr_length = SBYTES (bytestr); | 358 | ptrdiff_t bytestr_length = SBYTES (bytestr); |
| 431 | Lisp_Object *vectorp = XVECTOR (vector)->contents; | 359 | Lisp_Object *vectorp = XVECTOR (vector)->contents; |
| 432 | struct byte_stack stack; | ||
| 433 | 360 | ||
| 434 | stack.byte_string = bytestr; | 361 | unsigned char quitcounter = 1; |
| 435 | stack.pc = stack.byte_string_start = SDATA (bytestr); | ||
| 436 | unsigned char quitcounter = 0; | ||
| 437 | EMACS_INT stack_items = XFASTINT (maxdepth) + 1; | 362 | EMACS_INT stack_items = XFASTINT (maxdepth) + 1; |
| 438 | USE_SAFE_ALLOCA; | 363 | USE_SAFE_ALLOCA; |
| 439 | Lisp_Object *stack_base; | 364 | Lisp_Object *stack_base; |
| 440 | SAFE_ALLOCA_LISP (stack_base, stack_items); | 365 | SAFE_ALLOCA_LISP_EXTRA (stack_base, stack_items, bytestr_length); |
| 441 | Lisp_Object *stack_lim = stack_base + stack_items; | 366 | Lisp_Object *stack_lim = stack_base + stack_items; |
| 442 | Lisp_Object *top = stack_base; | 367 | Lisp_Object *top = stack_base; |
| 443 | stack.next = byte_stack_list; | 368 | memcpy (stack_lim, SDATA (bytestr), bytestr_length); |
| 444 | byte_stack_list = &stack; | 369 | void *void_stack_lim = stack_lim; |
| 370 | unsigned char const *bytestr_data = void_stack_lim; | ||
| 371 | unsigned char const *pc = bytestr_data; | ||
| 445 | ptrdiff_t count = SPECPDL_INDEX (); | 372 | ptrdiff_t count = SPECPDL_INDEX (); |
| 446 | 373 | ||
| 447 | if (!NILP (args_template)) | 374 | if (!NILP (args_template)) |
| @@ -585,11 +512,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 585 | op = FETCH2; | 512 | op = FETCH2; |
| 586 | v1 = POP; | 513 | v1 = POP; |
| 587 | if (NILP (v1)) | 514 | if (NILP (v1)) |
| 588 | { | 515 | goto op_branch; |
| 589 | BYTE_CODE_QUIT; | ||
| 590 | CHECK_RANGE (op); | ||
| 591 | stack.pc = stack.byte_string_start + op; | ||
| 592 | } | ||
| 593 | NEXT; | 516 | NEXT; |
| 594 | } | 517 | } |
| 595 | 518 | ||
| @@ -744,10 +667,22 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 744 | NEXT; | 667 | NEXT; |
| 745 | 668 | ||
| 746 | CASE (Bgoto): | 669 | CASE (Bgoto): |
| 747 | BYTE_CODE_QUIT; | 670 | op = FETCH2; |
| 748 | op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ | 671 | op_branch: |
| 749 | CHECK_RANGE (op); | 672 | op -= pc - bytestr_data; |
| 750 | stack.pc = stack.byte_string_start + op; | 673 | op_relative_branch: |
| 674 | if (BYTE_CODE_SAFE | ||
| 675 | && ! (bytestr_data - pc <= op | ||
| 676 | && op < bytestr_data + bytestr_length - pc)) | ||
| 677 | emacs_abort (); | ||
| 678 | quitcounter += op < 0; | ||
| 679 | if (!quitcounter) | ||
| 680 | { | ||
| 681 | quitcounter = 1; | ||
| 682 | maybe_gc (); | ||
| 683 | QUIT; | ||
| 684 | } | ||
| 685 | pc += op; | ||
| 751 | NEXT; | 686 | NEXT; |
| 752 | 687 | ||
| 753 | CASE (Bgotoifnonnil): | 688 | CASE (Bgotoifnonnil): |
| @@ -755,77 +690,58 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 755 | op = FETCH2; | 690 | op = FETCH2; |
| 756 | Lisp_Object v1 = POP; | 691 | Lisp_Object v1 = POP; |
| 757 | if (!NILP (v1)) | 692 | if (!NILP (v1)) |
| 758 | { | 693 | goto op_branch; |
| 759 | BYTE_CODE_QUIT; | ||
| 760 | CHECK_RANGE (op); | ||
| 761 | stack.pc = stack.byte_string_start + op; | ||
| 762 | } | ||
| 763 | NEXT; | 694 | NEXT; |
| 764 | } | 695 | } |
| 765 | 696 | ||
| 766 | CASE (Bgotoifnilelsepop): | 697 | CASE (Bgotoifnilelsepop): |
| 767 | op = FETCH2; | 698 | op = FETCH2; |
| 768 | if (NILP (TOP)) | 699 | if (NILP (TOP)) |
| 769 | { | 700 | goto op_branch; |
| 770 | BYTE_CODE_QUIT; | 701 | DISCARD (1); |
| 771 | CHECK_RANGE (op); | ||
| 772 | stack.pc = stack.byte_string_start + op; | ||
| 773 | } | ||
| 774 | else DISCARD (1); | ||
| 775 | NEXT; | 702 | NEXT; |
| 776 | 703 | ||
| 777 | CASE (Bgotoifnonnilelsepop): | 704 | CASE (Bgotoifnonnilelsepop): |
| 778 | op = FETCH2; | 705 | op = FETCH2; |
| 779 | if (!NILP (TOP)) | 706 | if (!NILP (TOP)) |
| 780 | { | 707 | goto op_branch; |
| 781 | BYTE_CODE_QUIT; | 708 | DISCARD (1); |
| 782 | CHECK_RANGE (op); | ||
| 783 | stack.pc = stack.byte_string_start + op; | ||
| 784 | } | ||
| 785 | else DISCARD (1); | ||
| 786 | NEXT; | 709 | NEXT; |
| 787 | 710 | ||
| 788 | CASE (BRgoto): | 711 | CASE (BRgoto): |
| 789 | BYTE_CODE_QUIT; | 712 | op = FETCH - 128; |
| 790 | stack.pc += (int) *stack.pc - 127; | 713 | goto op_relative_branch; |
| 791 | NEXT; | ||
| 792 | 714 | ||
| 793 | CASE (BRgotoifnil): | 715 | CASE (BRgotoifnil): |
| 794 | if (NILP (POP)) | 716 | { |
| 795 | { | 717 | Lisp_Object v1 = POP; |
| 796 | BYTE_CODE_QUIT; | 718 | op = FETCH - 128; |
| 797 | stack.pc += (int) *stack.pc - 128; | 719 | if (NILP (v1)) |
| 798 | } | 720 | goto op_relative_branch; |
| 799 | stack.pc++; | 721 | NEXT; |
| 800 | NEXT; | 722 | } |
| 801 | 723 | ||
| 802 | CASE (BRgotoifnonnil): | 724 | CASE (BRgotoifnonnil): |
| 803 | if (!NILP (POP)) | 725 | { |
| 804 | { | 726 | Lisp_Object v1 = POP; |
| 805 | BYTE_CODE_QUIT; | 727 | op = FETCH - 128; |
| 806 | stack.pc += (int) *stack.pc - 128; | 728 | if (!NILP (v1)) |
| 807 | } | 729 | goto op_relative_branch; |
| 808 | stack.pc++; | 730 | NEXT; |
| 809 | NEXT; | 731 | } |
| 810 | 732 | ||
| 811 | CASE (BRgotoifnilelsepop): | 733 | CASE (BRgotoifnilelsepop): |
| 812 | op = *stack.pc++; | 734 | op = FETCH - 128; |
| 813 | if (NILP (TOP)) | 735 | if (NILP (TOP)) |
| 814 | { | 736 | goto op_relative_branch; |
| 815 | BYTE_CODE_QUIT; | 737 | DISCARD (1); |
| 816 | stack.pc += op - 128; | ||
| 817 | } | ||
| 818 | else DISCARD (1); | ||
| 819 | NEXT; | 738 | NEXT; |
| 820 | 739 | ||
| 821 | CASE (BRgotoifnonnilelsepop): | 740 | CASE (BRgotoifnonnilelsepop): |
| 822 | op = *stack.pc++; | 741 | op = FETCH - 128; |
| 823 | if (!NILP (TOP)) | 742 | if (!NILP (TOP)) |
| 824 | { | 743 | goto op_relative_branch; |
| 825 | BYTE_CODE_QUIT; | 744 | DISCARD (1); |
| 826 | stack.pc += op - 128; | ||
| 827 | } | ||
| 828 | else DISCARD (1); | ||
| 829 | NEXT; | 745 | NEXT; |
| 830 | 746 | ||
| 831 | CASE (Breturn): | 747 | CASE (Breturn): |
| @@ -885,15 +801,11 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 885 | if (sys_setjmp (c->jmp)) | 801 | if (sys_setjmp (c->jmp)) |
| 886 | { | 802 | { |
| 887 | struct handler *c = handlerlist; | 803 | struct handler *c = handlerlist; |
| 888 | int dest; | ||
| 889 | top = c->bytecode_top; | 804 | top = c->bytecode_top; |
| 890 | dest = c->bytecode_dest; | 805 | op = c->bytecode_dest; |
| 891 | handlerlist = c->next; | 806 | handlerlist = c->next; |
| 892 | PUSH (c->val); | 807 | PUSH (c->val); |
| 893 | CHECK_RANGE (dest); | 808 | goto op_branch; |
| 894 | /* Might have been re-set by longjmp! */ | ||
| 895 | stack.byte_string_start = SDATA (stack.byte_string); | ||
| 896 | stack.pc = stack.byte_string_start + dest; | ||
| 897 | } | 809 | } |
| 898 | 810 | ||
| 899 | NEXT; | 811 | NEXT; |
| @@ -1461,7 +1373,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1461 | call3 (Qerror, | 1373 | call3 (Qerror, |
| 1462 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), | 1374 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), |
| 1463 | make_number (op), | 1375 | make_number (op), |
| 1464 | make_number (stack.pc - 1 - stack.byte_string_start)); | 1376 | make_number (pc - 1 - bytestr_data)); |
| 1465 | 1377 | ||
| 1466 | /* Handy byte-codes for lexical binding. */ | 1378 | /* Handy byte-codes for lexical binding. */ |
| 1467 | CASE (Bstack_ref1): | 1379 | CASE (Bstack_ref1): |
| @@ -1521,8 +1433,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1521 | 1433 | ||
| 1522 | exit: | 1434 | exit: |
| 1523 | 1435 | ||
| 1524 | byte_stack_list = byte_stack_list->next; | ||
| 1525 | |||
| 1526 | /* Binds and unbinds are supposed to be compiled balanced. */ | 1436 | /* Binds and unbinds are supposed to be compiled balanced. */ |
| 1527 | if (SPECPDL_INDEX () != count) | 1437 | if (SPECPDL_INDEX () != count) |
| 1528 | { | 1438 | { |