aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2016-08-09 00:37:40 -0700
committerPaul Eggert2016-08-09 01:31:22 -0700
commit644fc17b9ae181174a842e3876e887666d505666 (patch)
tree25fd8d1b3e1a32753d3db759d0909acbc2b12e77
parentcb71a119f7231984e010cc28ef33854721036a0f (diff)
downloademacs-644fc17b9ae181174a842e3876e887666d505666.tar.gz
emacs-644fc17b9ae181174a842e3876e887666d505666.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. (SAFE_ALLOCA_LISP_EXTRA): New macro, a generalization of SAFE_ALLOCA_LISP. (SAFE_ALLOCA_LISP): Use it.
-rw-r--r--etc/DEBUG2
-rw-r--r--src/.gdbinit15
-rw-r--r--src/alloc.c2
-rw-r--r--src/bytecode.c188
-rw-r--r--src/eval.c3
-rw-r--r--src/lisp.h13
6 files changed, 53 insertions, 170 deletions
diff --git a/etc/DEBUG b/etc/DEBUG
index d5d582902ab..656e29a8b74 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -282,7 +282,7 @@ type. Here are these commands:
282 xbufobjfwd xkbobjfwd xbuflocal xbuffer xsymbol xstring xvector xframe 282 xbufobjfwd xkbobjfwd xbuflocal xbuffer xsymbol xstring xvector xframe
283 xwinconfig xcompiled xcons xcar xcdr xsubr xprocess xfloat xscrollbar 283 xwinconfig xcompiled xcons xcar xcdr xsubr xprocess xfloat xscrollbar
284 xchartable xsubchartable xboolvector xhashtable xlist xcoding 284 xchartable xsubchartable xboolvector xhashtable xlist xcoding
285 xcharset xfontset xfont xbytecode 285 xcharset xfontset xfont
286 286
287Each one of them applies to a certain type or class of types. 287Each one of them applies to a certain type or class of types.
288(Some of these types are not visible in Lisp, because they exist only 288(Some of these types are not visible in Lisp, because they exist only
diff --git a/src/.gdbinit b/src/.gdbinit
index a4e9f709386..8e7ac3ce547 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 e25d91ff8aa..db165757e19 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -5799,8 +5799,6 @@ garbage_collect_1 (void *end)
5799 5799
5800 gc_sweep (); 5800 gc_sweep ();
5801 5801
5802 relocate_byte_stack ();
5803
5804 /* Clear the mark bits that we set in certain root slots. */ 5802 /* Clear the mark bits that we set in certain root slots. */
5805 VECTOR_UNMARK (&buffer_defaults); 5803 VECTOR_UNMARK (&buffer_defaults);
5806 VECTOR_UNMARK (&buffer_local_symbols); 5804 VECTOR_UNMARK (&buffer_local_symbols);
diff --git a/src/bytecode.c b/src/bytecode.c
index 0c5b8494d0c..995d37c09d5 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -281,59 +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. */
295 Lisp_Object byte_string;
296 const unsigned char *byte_string_start;
297
298 /* Next entry in byte_stack_list. */
299 struct byte_stack *next;
300};
301
302/* A list of currently active byte-code execution value stacks.
303 Fbyte_code adds an entry to the head of this list before it starts
304 processing byte-code, and it removes the entry again when it is
305 done. Signaling an error truncates the list. */
306
307struct byte_stack *byte_stack_list;
308
309
310/* Relocate program counters in the stacks on byte_stack_list. Called
311 when GC has completed. */
312
313void
314relocate_byte_stack (void)
315{
316 struct byte_stack *stack;
317
318 for (stack = byte_stack_list; 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 285
332#if BYTE_CODE_SAFE 286#define FETCH (*pc++)
333#define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)), *stack.pc++)
334#else
335#define FETCH *stack.pc++
336#endif
337 287
338/* 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
339 out of them. */ 289 out of them. */
@@ -358,32 +308,6 @@ relocate_byte_stack (void)
358 308
359#define TOP (*top) 309#define TOP (*top)
360 310
361/* Check for jumping out of range. */
362
363#define CHECK_RANGE(ARG) \
364 (BYTE_CODE_SAFE && bytestr_length <= (ARG) ? emacs_abort () : (void) 0)
365
366/* A version of the QUIT macro which makes sure that the stack top is
367 set before signaling `quit'. */
368
369#define BYTE_CODE_QUIT \
370 do { \
371 if (quitcounter++) \
372 break; \
373 maybe_gc (); \
374 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \
375 { \
376 Lisp_Object flag = Vquit_flag; \
377 Vquit_flag = Qnil; \
378 if (EQ (Vthrow_on_input, flag)) \
379 Fthrow (Vthrow_on_input, Qt); \
380 quit (); \
381 } \
382 else if (pending_signals) \
383 process_pending_signals (); \
384 } while (0)
385
386
387DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, 311DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0,
388 doc: /* Function used internally in byte-compiled code. 312 doc: /* Function used internally in byte-compiled code.
389The first argument, BYTESTR, is a string of byte code; 313The first argument, BYTESTR, is a string of byte code;
@@ -423,7 +347,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
423 Lisp_Object *vectorp; 347 Lisp_Object *vectorp;
424 ptrdiff_t const_length; 348 ptrdiff_t const_length;
425 ptrdiff_t bytestr_length; 349 ptrdiff_t bytestr_length;
426 struct byte_stack stack;
427 Lisp_Object *top; 350 Lisp_Object *top;
428 Lisp_Object result; 351 Lisp_Object result;
429 enum handlertype type; 352 enum handlertype type;
@@ -445,16 +368,16 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
445 bytestr_length = SBYTES (bytestr); 368 bytestr_length = SBYTES (bytestr);
446 vectorp = XVECTOR (vector)->contents; 369 vectorp = XVECTOR (vector)->contents;
447 370
448 stack.byte_string = bytestr; 371 unsigned char quitcounter = 1;
449 stack.pc = stack.byte_string_start = SDATA (bytestr);
450 unsigned char quitcounter = 0;
451 EMACS_INT stack_items = XFASTINT (maxdepth) + 1; 372 EMACS_INT stack_items = XFASTINT (maxdepth) + 1;
452 Lisp_Object *stack_base; 373 Lisp_Object *stack_base;
453 SAFE_ALLOCA_LISP (stack_base, stack_items); 374 SAFE_ALLOCA_LISP_EXTRA (stack_base, stack_items, bytestr_length);
454 Lisp_Object *stack_lim = stack_base + stack_items; 375 Lisp_Object *stack_lim = stack_base + stack_items;
455 top = stack_base; 376 top = stack_base;
456 stack.next = byte_stack_list; 377 memcpy (stack_lim, SDATA (bytestr), bytestr_length);
457 byte_stack_list = &stack; 378 void *void_stack_lim = stack_lim;
379 unsigned char const *bytestr_data = void_stack_lim;
380 unsigned char const *pc = bytestr_data;
458 ptrdiff_t count = SPECPDL_INDEX (); 381 ptrdiff_t count = SPECPDL_INDEX ();
459 382
460 if (!NILP (args_template)) 383 if (!NILP (args_template))
@@ -608,11 +531,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
608 op = FETCH2; 531 op = FETCH2;
609 v1 = POP; 532 v1 = POP;
610 if (NILP (v1)) 533 if (NILP (v1))
611 { 534 goto op_branch;
612 BYTE_CODE_QUIT;
613 CHECK_RANGE (op);
614 stack.pc = stack.byte_string_start + op;
615 }
616 NEXT; 535 NEXT;
617 } 536 }
618 537
@@ -791,10 +710,22 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
791 NEXT; 710 NEXT;
792 711
793 CASE (Bgoto): 712 CASE (Bgoto):
794 BYTE_CODE_QUIT; 713 op = FETCH2;
795 op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ 714 op_branch:
796 CHECK_RANGE (op); 715 op -= pc - bytestr_data;
797 stack.pc = stack.byte_string_start + op; 716 op_relative_branch:
717 if (BYTE_CODE_SAFE
718 && ! (bytestr_data - pc <= op
719 && op < bytestr_data + bytestr_length - pc))
720 emacs_abort ();
721 quitcounter += op < 0;
722 if (!quitcounter)
723 {
724 quitcounter = 1;
725 maybe_gc ();
726 QUIT;
727 }
728 pc += op;
798 NEXT; 729 NEXT;
799 730
800 CASE (Bgotoifnonnil): 731 CASE (Bgotoifnonnil):
@@ -803,51 +734,35 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
803 op = FETCH2; 734 op = FETCH2;
804 v1 = POP; 735 v1 = POP;
805 if (!NILP (v1)) 736 if (!NILP (v1))
806 { 737 goto op_branch;
807 BYTE_CODE_QUIT;
808 CHECK_RANGE (op);
809 stack.pc = stack.byte_string_start + op;
810 }
811 NEXT; 738 NEXT;
812 } 739 }
813 740
814 CASE (Bgotoifnilelsepop): 741 CASE (Bgotoifnilelsepop):
815 op = FETCH2; 742 op = FETCH2;
816 if (NILP (TOP)) 743 if (NILP (TOP))
817 { 744 goto op_branch;
818 BYTE_CODE_QUIT; 745 DISCARD (1);
819 CHECK_RANGE (op);
820 stack.pc = stack.byte_string_start + op;
821 }
822 else DISCARD (1);
823 NEXT; 746 NEXT;
824 747
825 CASE (Bgotoifnonnilelsepop): 748 CASE (Bgotoifnonnilelsepop):
826 op = FETCH2; 749 op = FETCH2;
827 if (!NILP (TOP)) 750 if (!NILP (TOP))
828 { 751 goto op_branch;
829 BYTE_CODE_QUIT; 752 DISCARD (1);
830 CHECK_RANGE (op);
831 stack.pc = stack.byte_string_start + op;
832 }
833 else DISCARD (1);
834 NEXT; 753 NEXT;
835 754
836 CASE (BRgoto): 755 CASE (BRgoto):
837 BYTE_CODE_QUIT; 756 op = FETCH - 128;
838 stack.pc += (int) *stack.pc - 127; 757 goto op_relative_branch;
839 NEXT;
840 758
841 CASE (BRgotoifnil): 759 CASE (BRgotoifnil):
842 { 760 {
843 Lisp_Object v1; 761 Lisp_Object v1;
844 v1 = POP; 762 v1 = POP;
763 op = FETCH - 128;
845 if (NILP (v1)) 764 if (NILP (v1))
846 { 765 goto op_relative_branch;
847 BYTE_CODE_QUIT;
848 stack.pc += (int) *stack.pc - 128;
849 }
850 stack.pc++;
851 NEXT; 766 NEXT;
852 } 767 }
853 768
@@ -855,33 +770,24 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
855 { 770 {
856 Lisp_Object v1; 771 Lisp_Object v1;
857 v1 = POP; 772 v1 = POP;
773 op = FETCH - 128;
858 if (!NILP (v1)) 774 if (!NILP (v1))
859 { 775 goto op_relative_branch;
860 BYTE_CODE_QUIT;
861 stack.pc += (int) *stack.pc - 128;
862 }
863 stack.pc++;
864 NEXT; 776 NEXT;
865 } 777 }
866 778
867 CASE (BRgotoifnilelsepop): 779 CASE (BRgotoifnilelsepop):
868 op = *stack.pc++; 780 op = FETCH - 128;
869 if (NILP (TOP)) 781 if (NILP (TOP))
870 { 782 goto op_relative_branch;
871 BYTE_CODE_QUIT; 783 DISCARD (1);
872 stack.pc += op - 128;
873 }
874 else DISCARD (1);
875 NEXT; 784 NEXT;
876 785
877 CASE (BRgotoifnonnilelsepop): 786 CASE (BRgotoifnonnilelsepop):
878 op = *stack.pc++; 787 op = FETCH - 128;
879 if (!NILP (TOP)) 788 if (!NILP (TOP))
880 { 789 goto op_relative_branch;
881 BYTE_CODE_QUIT; 790 DISCARD (1);
882 stack.pc += op - 128;
883 }
884 else DISCARD (1);
885 NEXT; 791 NEXT;
886 792
887 CASE (Breturn): 793 CASE (Breturn):
@@ -946,15 +852,11 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
946 if (sys_setjmp (c->jmp)) 852 if (sys_setjmp (c->jmp))
947 { 853 {
948 struct handler *c = handlerlist; 854 struct handler *c = handlerlist;
949 int dest;
950 top = c->bytecode_top; 855 top = c->bytecode_top;
951 dest = c->bytecode_dest; 856 op = c->bytecode_dest;
952 handlerlist = c->next; 857 handlerlist = c->next;
953 PUSH (c->val); 858 PUSH (c->val);
954 CHECK_RANGE (dest); 859 goto op_branch;
955 /* Might have been re-set by longjmp! */
956 stack.byte_string_start = SDATA (stack.byte_string);
957 stack.pc = stack.byte_string_start + dest;
958 } 860 }
959 861
960 NEXT; 862 NEXT;
@@ -1629,7 +1531,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
1629 call3 (Qerror, 1531 call3 (Qerror,
1630 build_string ("Invalid byte opcode: op=%s, ptr=%d"), 1532 build_string ("Invalid byte opcode: op=%s, ptr=%d"),
1631 make_number (op), 1533 make_number (op),
1632 make_number ((stack.pc - 1) - stack.byte_string_start)); 1534 make_number (pc - 1 - bytestr_data));
1633 1535
1634 /* Handy byte-codes for lexical binding. */ 1536 /* Handy byte-codes for lexical binding. */
1635 CASE (Bstack_ref1): 1537 CASE (Bstack_ref1):
@@ -1689,8 +1591,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
1689 1591
1690 exit: 1592 exit:
1691 1593
1692 byte_stack_list = byte_stack_list->next;
1693
1694 /* Binds and unbinds are supposed to be compiled balanced. */ 1594 /* Binds and unbinds are supposed to be compiled balanced. */
1695 if (SPECPDL_INDEX () != count) 1595 if (SPECPDL_INDEX () != count)
1696 { 1596 {
diff --git a/src/eval.c b/src/eval.c
index 7b7bdd8df7b..f681ef7c278 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -222,7 +222,6 @@ static struct handler handlerlist_sentinel;
222void 222void
223init_eval (void) 223init_eval (void)
224{ 224{
225 byte_stack_list = 0;
226 specpdl_ptr = specpdl; 225 specpdl_ptr = specpdl;
227 { /* Put a dummy catcher at top-level so that handlerlist is never NULL. 226 { /* Put a dummy catcher at top-level so that handlerlist is never NULL.
228 This is important since handlerlist->nextfree holds the freelist 227 This is important since handlerlist->nextfree holds the freelist
@@ -1135,7 +1134,6 @@ unwind_to_catch (struct handler *catch, Lisp_Object value)
1135 1134
1136 eassert (handlerlist == catch); 1135 eassert (handlerlist == catch);
1137 1136
1138 byte_stack_list = catch->byte_stack;
1139 lisp_eval_depth = catch->lisp_eval_depth; 1137 lisp_eval_depth = catch->lisp_eval_depth;
1140 1138
1141 sys_longjmp (catch->jmp, 1); 1139 sys_longjmp (catch->jmp, 1);
@@ -1430,7 +1428,6 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
1430 c->pdlcount = SPECPDL_INDEX (); 1428 c->pdlcount = SPECPDL_INDEX ();
1431 c->poll_suppress_count = poll_suppress_count; 1429 c->poll_suppress_count = poll_suppress_count;
1432 c->interrupt_input_blocked = interrupt_input_blocked; 1430 c->interrupt_input_blocked = interrupt_input_blocked;
1433 c->byte_stack = byte_stack_list;
1434 handlerlist = c; 1431 handlerlist = c;
1435 return c; 1432 return c;
1436} 1433}
diff --git a/src/lisp.h b/src/lisp.h
index 8ac9cc1d2a9..97c8d9fe84f 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3202,7 +3202,6 @@ struct handler
3202 ptrdiff_t pdlcount; 3202 ptrdiff_t pdlcount;
3203 int poll_suppress_count; 3203 int poll_suppress_count;
3204 int interrupt_input_blocked; 3204 int interrupt_input_blocked;
3205 struct byte_stack *byte_stack;
3206}; 3205};
3207 3206
3208extern Lisp_Object memory_signal_data; 3207extern Lisp_Object memory_signal_data;
@@ -4231,8 +4230,6 @@ extern int read_bytecode_char (bool);
4231 4230
4232/* Defined in bytecode.c. */ 4231/* Defined in bytecode.c. */
4233extern void syms_of_bytecode (void); 4232extern void syms_of_bytecode (void);
4234extern struct byte_stack *byte_stack_list;
4235extern void relocate_byte_stack (void);
4236extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object, 4233extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object,
4237 Lisp_Object, ptrdiff_t, Lisp_Object *); 4234 Lisp_Object, ptrdiff_t, Lisp_Object *);
4238extern Lisp_Object get_byte_code_arity (Lisp_Object); 4235extern Lisp_Object get_byte_code_arity (Lisp_Object);
@@ -4530,12 +4527,14 @@ extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1));
4530 } \ 4527 } \
4531 } while (false) 4528 } while (false)
4532 4529
4533/* SAFE_ALLOCA_LISP allocates an array of Lisp_Objects. */ 4530/* Set BUF to point to an allocated array of NELT Lisp_Objects,
4531 immediately followed by EXTRA spare bytes. */
4534 4532
4535#define SAFE_ALLOCA_LISP(buf, nelt) \ 4533#define SAFE_ALLOCA_LISP_EXTRA(buf, nelt, extra) \
4536 do { \ 4534 do { \
4537 ptrdiff_t alloca_nbytes; \ 4535 ptrdiff_t alloca_nbytes; \
4538 if (INT_MULTIPLY_WRAPV (nelt, word_size, &alloca_nbytes) \ 4536 if (INT_MULTIPLY_WRAPV (nelt, word_size, &alloca_nbytes) \
4537 || INT_ADD_WRAPV (alloca_nbytes, extra, &alloca_nbytes) \
4539 || SIZE_MAX < alloca_nbytes) \ 4538 || SIZE_MAX < alloca_nbytes) \
4540 memory_full (SIZE_MAX); \ 4539 memory_full (SIZE_MAX); \
4541 else if (alloca_nbytes <= sa_avail) \ 4540 else if (alloca_nbytes <= sa_avail) \
@@ -4550,6 +4549,10 @@ extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1));
4550 } \ 4549 } \
4551 } while (false) 4550 } while (false)
4552 4551
4552/* Set BUF to point to an allocated array of NELT Lisp_Objects. */
4553
4554#define SAFE_ALLOCA_LISP(buf, nelt) SAFE_ALLOCA_LISP_EXTRA (buf, nelt, 0)
4555
4553 4556
4554/* If USE_STACK_LISP_OBJECTS, define macros that and functions that allocate 4557/* If USE_STACK_LISP_OBJECTS, define macros that and functions that allocate
4555 block-scoped conses and strings. These objects are not 4558 block-scoped conses and strings. These objects are not