aboutsummaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/.gdbinit15
-rw-r--r--src/alloc.c2
-rw-r--r--src/bytecode.c200
-rw-r--r--src/eval.c3
-rw-r--r--src/lisp.h2
-rw-r--r--src/thread.c16
-rw-r--r--src/thread.h10
7 files changed, 59 insertions, 189 deletions
diff --git a/src/.gdbinit b/src/.gdbinit
index 9160ffa439e..b0c0dfd7e90 100644
--- a/src/.gdbinit
+++ b/src/.gdbinit
@@ -1215,21 +1215,6 @@ document xwhichsymbols
1215 maximum number of symbols referencing it to produce. 1215 maximum number of symbols referencing it to produce.
1216end 1216end
1217 1217
1218define xbytecode
1219 set $bt = byte_stack_list
1220 while $bt
1221 xgetptr $bt->byte_string
1222 set $ptr = (struct Lisp_String *) $ptr
1223 xprintbytestr $ptr
1224 printf "\n0x%x => ", $bt->byte_string
1225 xwhichsymbols $bt->byte_string 5
1226 set $bt = $bt->next
1227 end
1228end
1229document xbytecode
1230 Print a backtrace of the byte code stack.
1231end
1232
1233# Show Lisp backtrace after normal backtrace. 1218# Show Lisp backtrace after normal backtrace.
1234define hookpost-backtrace 1219define hookpost-backtrace
1235 set $bt = backtrace_top () 1220 set $bt = backtrace_top ()
diff --git a/src/alloc.c b/src/alloc.c
index 93ea286cfb8..121d7042353 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -5883,8 +5883,6 @@ garbage_collect_1 (void *end)
5883 5883
5884 gc_sweep (); 5884 gc_sweep ();
5885 5885
5886 unmark_threads ();
5887
5888 /* Clear the mark bits that we set in certain root slots. */ 5886 /* Clear the mark bits that we set in certain root slots. */
5889 VECTOR_UNMARK (&buffer_defaults); 5887 VECTOR_UNMARK (&buffer_defaults);
5890 VECTOR_UNMARK (&buffer_local_symbols); 5888 VECTOR_UNMARK (&buffer_local_symbols);
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 {
diff --git a/src/eval.c b/src/eval.c
index 1313093a533..ddcccc285d3 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -239,7 +239,6 @@ init_eval_once (void)
239void 239void
240init_eval (void) 240init_eval (void)
241{ 241{
242 byte_stack_list = 0;
243 specpdl_ptr = specpdl; 242 specpdl_ptr = specpdl;
244 { /* Put a dummy catcher at top-level so that handlerlist is never NULL. 243 { /* Put a dummy catcher at top-level so that handlerlist is never NULL.
245 This is important since handlerlist->nextfree holds the freelist 244 This is important since handlerlist->nextfree holds the freelist
@@ -1156,7 +1155,6 @@ unwind_to_catch (struct handler *catch, Lisp_Object value)
1156 1155
1157 eassert (handlerlist == catch); 1156 eassert (handlerlist == catch);
1158 1157
1159 byte_stack_list = catch->byte_stack;
1160 lisp_eval_depth = catch->f_lisp_eval_depth; 1158 lisp_eval_depth = catch->f_lisp_eval_depth;
1161 1159
1162 sys_longjmp (catch->jmp, 1); 1160 sys_longjmp (catch->jmp, 1);
@@ -1451,7 +1449,6 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
1451 c->pdlcount = SPECPDL_INDEX (); 1449 c->pdlcount = SPECPDL_INDEX ();
1452 c->poll_suppress_count = poll_suppress_count; 1450 c->poll_suppress_count = poll_suppress_count;
1453 c->interrupt_input_blocked = interrupt_input_blocked; 1451 c->interrupt_input_blocked = interrupt_input_blocked;
1454 c->byte_stack = byte_stack_list;
1455 handlerlist = c; 1452 handlerlist = c;
1456 return c; 1453 return c;
1457} 1454}
diff --git a/src/lisp.h b/src/lisp.h
index 79b208a333b..75a7fd3d53d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3282,7 +3282,6 @@ struct handler
3282 ptrdiff_t pdlcount; 3282 ptrdiff_t pdlcount;
3283 int poll_suppress_count; 3283 int poll_suppress_count;
3284 int interrupt_input_blocked; 3284 int interrupt_input_blocked;
3285 struct byte_stack *byte_stack;
3286}; 3285};
3287 3286
3288extern Lisp_Object memory_signal_data; 3287extern Lisp_Object memory_signal_data;
@@ -4330,7 +4329,6 @@ extern int read_bytecode_char (bool);
4330 4329
4331/* Defined in bytecode.c. */ 4330/* Defined in bytecode.c. */
4332extern void syms_of_bytecode (void); 4331extern void syms_of_bytecode (void);
4333extern void relocate_byte_stack (struct byte_stack *);
4334extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object, 4332extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object,
4335 Lisp_Object, ptrdiff_t, Lisp_Object *); 4333 Lisp_Object, ptrdiff_t, Lisp_Object *);
4336extern Lisp_Object get_byte_code_arity (Lisp_Object); 4334extern Lisp_Object get_byte_code_arity (Lisp_Object);
diff --git a/src/thread.c b/src/thread.c
index 0bb0b7e006a..560d2cfa74f 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -595,16 +595,6 @@ mark_threads (void)
595 flush_stack_call_func (mark_threads_callback, NULL); 595 flush_stack_call_func (mark_threads_callback, NULL);
596} 596}
597 597
598void
599unmark_threads (void)
600{
601 struct thread_state *iter;
602
603 for (iter = all_threads; iter; iter = iter->next_thread)
604 if (iter->m_byte_stack_list)
605 relocate_byte_stack (iter->m_byte_stack_list);
606}
607
608 598
609 599
610static void 600static void
@@ -716,7 +706,7 @@ If NAME is given, it must be a string; it names the new thread. */)
716 struct thread_state *new_thread; 706 struct thread_state *new_thread;
717 Lisp_Object result; 707 Lisp_Object result;
718 const char *c_name = NULL; 708 const char *c_name = NULL;
719 size_t offset = offsetof (struct thread_state, m_byte_stack_list); 709 size_t offset = offsetof (struct thread_state, m_stack_bottom);
720 710
721 /* Can't start a thread in temacs. */ 711 /* Can't start a thread in temacs. */
722 if (!initialized) 712 if (!initialized)
@@ -725,7 +715,7 @@ If NAME is given, it must be a string; it names the new thread. */)
725 if (!NILP (name)) 715 if (!NILP (name))
726 CHECK_STRING (name); 716 CHECK_STRING (name);
727 717
728 new_thread = ALLOCATE_PSEUDOVECTOR (struct thread_state, m_byte_stack_list, 718 new_thread = ALLOCATE_PSEUDOVECTOR (struct thread_state, m_stack_bottom,
729 PVEC_THREAD); 719 PVEC_THREAD);
730 memset ((char *) new_thread + offset, 0, 720 memset ((char *) new_thread + offset, 0,
731 sizeof (struct thread_state) - offset); 721 sizeof (struct thread_state) - offset);
@@ -940,7 +930,7 @@ static void
940init_primary_thread (void) 930init_primary_thread (void)
941{ 931{
942 primary_thread.header.size 932 primary_thread.header.size
943 = PSEUDOVECSIZE (struct thread_state, m_byte_stack_list); 933 = PSEUDOVECSIZE (struct thread_state, m_stack_bottom);
944 XSETPVECTYPE (&primary_thread, PVEC_THREAD); 934 XSETPVECTYPE (&primary_thread, PVEC_THREAD);
945 primary_thread.m_last_thing_searched = Qnil; 935 primary_thread.m_last_thing_searched = Qnil;
946 primary_thread.m_saved_last_thing_searched = Qnil; 936 primary_thread.m_saved_last_thing_searched = Qnil;
diff --git a/src/thread.h b/src/thread.h
index 33f8ea70636..b8524014ea4 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -56,14 +56,7 @@ struct thread_state
56 waiting on. */ 56 waiting on. */
57 Lisp_Object event_object; 57 Lisp_Object event_object;
58 58
59 /* m_byte_stack_list must be the first non-lisp field. */ 59 /* m_stack_bottom must be the first non-Lisp field. */
60 /* A list of currently active byte-code execution value stacks.
61 Fbyte_code adds an entry to the head of this list before it starts
62 processing byte-code, and it removed the entry again when it is
63 done. Signaling an error truncates the list. */
64 struct byte_stack *m_byte_stack_list;
65#define byte_stack_list (current_thread->m_byte_stack_list)
66
67 /* An address near the bottom of the stack. 60 /* An address near the bottom of the stack.
68 Tells GC how to save a copy of the stack. */ 61 Tells GC how to save a copy of the stack. */
69 char *m_stack_bottom; 62 char *m_stack_bottom;
@@ -227,7 +220,6 @@ struct Lisp_CondVar
227 220
228extern struct thread_state *current_thread; 221extern struct thread_state *current_thread;
229 222
230extern void unmark_threads (void);
231extern void finalize_one_thread (struct thread_state *state); 223extern void finalize_one_thread (struct thread_state *state);
232extern void finalize_one_mutex (struct Lisp_Mutex *); 224extern void finalize_one_mutex (struct Lisp_Mutex *);
233extern void finalize_one_condvar (struct Lisp_CondVar *); 225extern void finalize_one_condvar (struct Lisp_CondVar *);