aboutsummaryrefslogtreecommitdiffstats
path: root/src/bytecode.c
diff options
context:
space:
mode:
authorPaul Eggert2016-12-23 21:13:58 -0800
committerPaul Eggert2016-12-23 21:46:53 -0800
commita815e5f19581344af5e143636039064a7fbe83ed (patch)
treef5ed9c34657f1a86d85020d30826d07d9fa4d56b /src/bytecode.c
parenta43cfb1ad55cad553d54798356c69e2496a3e504 (diff)
downloademacs-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.c200
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
287struct 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
315void
316relocate_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
383DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, 311DEFUN ("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.
385The first argument, BYTESTR, is a string of byte code; 313The 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 {