From 078d2d37f2f6cf7478931810d099c2581ed5db29 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 23 Dec 2016 19:01:36 -0800 Subject: BYTE_CODE_SAFE cleanups * src/bytecode.c (BYTE_MAINTAIN_TOP): Remove; no longer needed. (struct byte_stack) [BYTE_MAINTAIN_TOP]: Remove unused members ‘top’ and ‘bottom’. (exec_byte_code): Nest inside { } to avoid GCC warning about jumping over declaration when compiled with -DBYTE_CODE_SAFE. --- src/bytecode.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'src/bytecode.c') diff --git a/src/bytecode.c b/src/bytecode.c index c581ed6d982..06a800bef49 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -280,9 +280,6 @@ enum byte_code_op Bset_mark = 0163, /* this loser is no longer generated as of v18 */ #endif }; - -/* Whether to maintain a `top' and `bottom' field in the stack frame. */ -#define BYTE_MAINTAIN_TOP BYTE_CODE_SAFE /* Structure describing a value stack used during byte-code execution in Fbyte_code. */ @@ -293,12 +290,6 @@ struct byte_stack and is relocated when that string is relocated. */ const unsigned char *pc; - /* Top and bottom of stack. The bottom points to an area of memory - allocated with alloca in Fbyte_code. */ -#if BYTE_MAINTAIN_TOP - Lisp_Object *top, *bottom; -#endif - /* The string containing the byte-code, and its current address. Storing this here protects it from GC because mark_byte_stack marks it. */ @@ -760,15 +751,17 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, NEXT; CASE (Bgotoifnonnil): - op = FETCH2; - Lisp_Object v1 = POP; - if (!NILP (v1)) - { - BYTE_CODE_QUIT; - CHECK_RANGE (op); - stack.pc = stack.byte_string_start + op; - } - NEXT; + { + op = FETCH2; + Lisp_Object v1 = POP; + if (!NILP (v1)) + { + BYTE_CODE_QUIT; + CHECK_RANGE (op); + stack.pc = stack.byte_string_start + op; + } + NEXT; + } CASE (Bgotoifnilelsepop): op = FETCH2; -- cgit v1.2.1 From a43cfb1ad55cad553d54798356c69e2496a3e504 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 23 Dec 2016 20:30:11 -0800 Subject: BYTE_CODE_SAFE typo fix * src/bytecode.c (FETCH): Depend on the value of BYTE_CODE_SAFE, not on whether it is defined. --- src/bytecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bytecode.c') diff --git a/src/bytecode.c b/src/bytecode.c index 06a800bef49..5e0055f4ee4 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -328,7 +328,7 @@ relocate_byte_stack (struct byte_stack *stack) /* Fetch the next byte from the bytecode stream. */ -#ifdef BYTE_CODE_SAFE +#if BYTE_CODE_SAFE #define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)), *stack.pc++) #else #define FETCH *stack.pc++ -- cgit v1.2.1 From a815e5f19581344af5e143636039064a7fbe83ed Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 23 Dec 2016 21:13:58 -0800 Subject: 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. --- src/bytecode.c | 200 ++++++++++++++++----------------------------------------- 1 file changed, 55 insertions(+), 145 deletions(-) (limited to 'src/bytecode.c') 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 #endif }; -/* Structure describing a value stack used during byte-code execution - in Fbyte_code. */ - -struct byte_stack -{ - /* Program counter. This points into the byte_string below - and is relocated when that string is relocated. */ - const unsigned char *pc; - - /* The string containing the byte-code, and its current address. - Storing this here protects it from GC because mark_byte_stack - marks it. */ - Lisp_Object byte_string; - const unsigned char *byte_string_start; - - /* Next entry in byte_stack_list. */ - struct byte_stack *next; -}; - -/* A list of currently active byte-code execution value stacks. - Fbyte_code adds an entry to the head of this list before it starts - processing byte-code, and it removes the entry again when it is - done. Signaling an error truncates the list. - - byte_stack_list is a macro defined in thread.h. */ -/* struct byte_stack *byte_stack_list; */ - - -/* Relocate program counters in the stacks on byte_stack_list. Called - when GC has completed. */ - -void -relocate_byte_stack (struct byte_stack *stack) -{ - for (; stack; stack = stack->next) - { - if (stack->byte_string_start != SDATA (stack->byte_string)) - { - ptrdiff_t offset = stack->pc - stack->byte_string_start; - stack->byte_string_start = SDATA (stack->byte_string); - stack->pc = stack->byte_string_start + offset; - } - } -} - - /* Fetch the next byte from the bytecode stream. */ -#if BYTE_CODE_SAFE -#define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)), *stack.pc++) -#else -#define FETCH *stack.pc++ -#endif + +#define FETCH (*pc++) /* Fetch two bytes from the bytecode stream and make a 16-bit number out of them. */ @@ -357,29 +308,6 @@ relocate_byte_stack (struct byte_stack *stack) #define TOP (*top) -#define CHECK_RANGE(ARG) \ - (BYTE_CODE_SAFE && bytestr_length <= (ARG) ? emacs_abort () : (void) 0) - -/* A version of the QUIT macro which makes sure that the stack top is - set before signaling `quit'. */ -#define BYTE_CODE_QUIT \ - do { \ - if (quitcounter++) \ - break; \ - maybe_gc (); \ - if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \ - { \ - Lisp_Object flag = Vquit_flag; \ - Vquit_flag = Qnil; \ - if (EQ (Vthrow_on_input, flag)) \ - Fthrow (Vthrow_on_input, Qt); \ - quit (); \ - } \ - else if (pending_signals) \ - process_pending_signals (); \ - } while (0) - - DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, doc: /* Function used internally in byte-compiled code. 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, ptrdiff_t bytestr_length = SBYTES (bytestr); Lisp_Object *vectorp = XVECTOR (vector)->contents; - struct byte_stack stack; - stack.byte_string = bytestr; - stack.pc = stack.byte_string_start = SDATA (bytestr); - unsigned char quitcounter = 0; + unsigned char quitcounter = 1; EMACS_INT stack_items = XFASTINT (maxdepth) + 1; USE_SAFE_ALLOCA; Lisp_Object *stack_base; - SAFE_ALLOCA_LISP (stack_base, stack_items); + SAFE_ALLOCA_LISP_EXTRA (stack_base, stack_items, bytestr_length); Lisp_Object *stack_lim = stack_base + stack_items; Lisp_Object *top = stack_base; - stack.next = byte_stack_list; - byte_stack_list = &stack; + memcpy (stack_lim, SDATA (bytestr), bytestr_length); + void *void_stack_lim = stack_lim; + unsigned char const *bytestr_data = void_stack_lim; + unsigned char const *pc = bytestr_data; ptrdiff_t count = SPECPDL_INDEX (); if (!NILP (args_template)) @@ -585,11 +512,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, op = FETCH2; v1 = POP; if (NILP (v1)) - { - BYTE_CODE_QUIT; - CHECK_RANGE (op); - stack.pc = stack.byte_string_start + op; - } + goto op_branch; NEXT; } @@ -744,10 +667,22 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, NEXT; CASE (Bgoto): - BYTE_CODE_QUIT; - op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ - CHECK_RANGE (op); - stack.pc = stack.byte_string_start + op; + op = FETCH2; + op_branch: + op -= pc - bytestr_data; + op_relative_branch: + if (BYTE_CODE_SAFE + && ! (bytestr_data - pc <= op + && op < bytestr_data + bytestr_length - pc)) + emacs_abort (); + quitcounter += op < 0; + if (!quitcounter) + { + quitcounter = 1; + maybe_gc (); + QUIT; + } + pc += op; NEXT; CASE (Bgotoifnonnil): @@ -755,77 +690,58 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, op = FETCH2; Lisp_Object v1 = POP; if (!NILP (v1)) - { - BYTE_CODE_QUIT; - CHECK_RANGE (op); - stack.pc = stack.byte_string_start + op; - } + goto op_branch; NEXT; } CASE (Bgotoifnilelsepop): op = FETCH2; if (NILP (TOP)) - { - BYTE_CODE_QUIT; - CHECK_RANGE (op); - stack.pc = stack.byte_string_start + op; - } - else DISCARD (1); + goto op_branch; + DISCARD (1); NEXT; CASE (Bgotoifnonnilelsepop): op = FETCH2; if (!NILP (TOP)) - { - BYTE_CODE_QUIT; - CHECK_RANGE (op); - stack.pc = stack.byte_string_start + op; - } - else DISCARD (1); + goto op_branch; + DISCARD (1); NEXT; CASE (BRgoto): - BYTE_CODE_QUIT; - stack.pc += (int) *stack.pc - 127; - NEXT; + op = FETCH - 128; + goto op_relative_branch; CASE (BRgotoifnil): - if (NILP (POP)) - { - BYTE_CODE_QUIT; - stack.pc += (int) *stack.pc - 128; - } - stack.pc++; - NEXT; + { + Lisp_Object v1 = POP; + op = FETCH - 128; + if (NILP (v1)) + goto op_relative_branch; + NEXT; + } CASE (BRgotoifnonnil): - if (!NILP (POP)) - { - BYTE_CODE_QUIT; - stack.pc += (int) *stack.pc - 128; - } - stack.pc++; - NEXT; + { + Lisp_Object v1 = POP; + op = FETCH - 128; + if (!NILP (v1)) + goto op_relative_branch; + NEXT; + } CASE (BRgotoifnilelsepop): - op = *stack.pc++; + op = FETCH - 128; if (NILP (TOP)) - { - BYTE_CODE_QUIT; - stack.pc += op - 128; - } - else DISCARD (1); + goto op_relative_branch; + DISCARD (1); NEXT; CASE (BRgotoifnonnilelsepop): - op = *stack.pc++; + op = FETCH - 128; if (!NILP (TOP)) - { - BYTE_CODE_QUIT; - stack.pc += op - 128; - } - else DISCARD (1); + goto op_relative_branch; + DISCARD (1); NEXT; CASE (Breturn): @@ -885,15 +801,11 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, if (sys_setjmp (c->jmp)) { struct handler *c = handlerlist; - int dest; top = c->bytecode_top; - dest = c->bytecode_dest; + op = c->bytecode_dest; handlerlist = c->next; PUSH (c->val); - CHECK_RANGE (dest); - /* Might have been re-set by longjmp! */ - stack.byte_string_start = SDATA (stack.byte_string); - stack.pc = stack.byte_string_start + dest; + goto op_branch; } NEXT; @@ -1461,7 +1373,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, call3 (Qerror, build_string ("Invalid byte opcode: op=%s, ptr=%d"), make_number (op), - make_number (stack.pc - 1 - stack.byte_string_start)); + make_number (pc - 1 - bytestr_data)); /* Handy byte-codes for lexical binding. */ CASE (Bstack_ref1): @@ -1521,8 +1433,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, exit: - byte_stack_list = byte_stack_list->next; - /* Binds and unbinds are supposed to be compiled balanced. */ if (SPECPDL_INDEX () != count) { -- cgit v1.2.1 From e36a3882c338765a9ddfebfc160e5a298933f233 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 23 Dec 2016 21:38:59 -0800 Subject: Simplify exec_byte_code via moving decls etc. * src/bytecode.c (exec_byte_code): Simplify, mostly by moving initializers into decls, and by omitting some unnecessary changes to ‘top’. --- src/bytecode.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'src/bytecode.c') diff --git a/src/bytecode.c b/src/bytecode.c index 51546ca474d..d484dbb25c6 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -508,9 +508,8 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, CASE (Bgotoifnil): { - Lisp_Object v1; + Lisp_Object v1 = POP; op = FETCH2; - v1 = POP; if (NILP (v1)) goto op_branch; NEXT; @@ -686,13 +685,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, NEXT; CASE (Bgotoifnonnil): - { - op = FETCH2; - Lisp_Object v1 = POP; - if (!NILP (v1)) - goto op_branch; - NEXT; - } + op = FETCH2; + if (!NILP (POP)) + goto op_branch; + NEXT; CASE (Bgotoifnilelsepop): op = FETCH2; @@ -713,22 +709,16 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, goto op_relative_branch; CASE (BRgotoifnil): - { - Lisp_Object v1 = POP; - op = FETCH - 128; - if (NILP (v1)) - goto op_relative_branch; - NEXT; - } + op = FETCH - 128; + if (NILP (POP)) + goto op_relative_branch; + NEXT; CASE (BRgotoifnonnil): - { - Lisp_Object v1 = POP; - op = FETCH - 128; - if (!NILP (v1)) - goto op_relative_branch; - NEXT; - } + op = FETCH - 128; + if (!NILP (POP)) + goto op_relative_branch; + NEXT; CASE (BRgotoifnilelsepop): op = FETCH - 128; @@ -1248,9 +1238,9 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, CASE (Bdowncase): TOP = Fdowncase (TOP); - NEXT; + NEXT; - CASE (Bstringeqlsign): + CASE (Bstringeqlsign): { Lisp_Object v1 = POP; TOP = Fstring_equal (TOP, v1); -- cgit v1.2.1 From a02ca7a231c3856efd57a502c6a73e6c251091e8 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 27 Dec 2016 10:32:44 -0800 Subject: Simplify prog1 implementation Inspired by a suggestion from Chris Gregory in: http://lists.gnu.org/archive/html/emacs-devel/2016-12/msg00965.html On my platform, this generates exactly the same machine insns. * src/eval.c (prog_ignore): Rename from unwind_body, since it’s more general than that. All callers changed. (Fprog1): Simplify by using prog_ignore. (Fwhile): Clarify by using prog_ignore. --- src/bytecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bytecode.c') diff --git a/src/bytecode.c b/src/bytecode.c index d484dbb25c6..3bb96c2ed2d 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -809,7 +809,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, { Lisp_Object handler = POP; /* Support for a function here is new in 24.4. */ - record_unwind_protect (FUNCTIONP (handler) ? bcall0 : unwind_body, + record_unwind_protect (FUNCTIONP (handler) ? bcall0 : prog_ignore, handler); NEXT; } -- cgit v1.2.1 From 5badc81c1cdfbb261ad3e6d1b753defb15712f26 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 1 Jan 2017 03:14:01 +0000 Subject: Update copyright year to 2017 Run admin/update-copyright. --- src/bytecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bytecode.c') diff --git a/src/bytecode.c b/src/bytecode.c index 9ae2e820d51..fa942fc4e1b 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -1,5 +1,5 @@ /* Execution of byte code produced by bytecomp.el. - Copyright (C) 1985-1988, 1993, 2000-2016 Free Software Foundation, + Copyright (C) 1985-1988, 1993, 2000-2017 Free Software Foundation, Inc. This file is part of GNU Emacs. -- cgit v1.2.1 From b3a3ed526d2c490c9c5605707f0cd7bff3c88693 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 25 Jan 2017 21:13:19 -0800 Subject: Replace QUIT with maybe_quit There’s no longer need to have QUIT stand for a slug of C statements. Use the more-obvious function-call syntax instead. Also, use true and false when setting immediate_quit. These changes should not affect the generated machine code. * src/lisp.h (QUIT): Remove. All uses replaced by maybe_quit. --- src/bytecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bytecode.c') diff --git a/src/bytecode.c b/src/bytecode.c index a64bc171d14..499fb881e2e 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -679,7 +679,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, { quitcounter = 1; maybe_gc (); - QUIT; + maybe_quit (); } pc += op; NEXT; -- cgit v1.2.1