From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Tom Tromey Newsgroups: gmane.emacs.devel Subject: Re: Inefficiency in Bgotoifnil byte-code instruction Date: Mon, 02 Jul 2012 13:17:37 -0600 Message-ID: <87y5n2vupa.fsf@fleche.redhat.com> References: <87k3yq2htz.fsf@fleche.redhat.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: dough.gmane.org 1341256682 19816 80.91.229.3 (2 Jul 2012 19:18:02 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Mon, 2 Jul 2012 19:18:02 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Jul 02 21:18:01 2012 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Slm8H-0003h0-76 for ged-emacs-devel@m.gmane.org; Mon, 02 Jul 2012 21:18:01 +0200 Original-Received: from localhost ([::1]:36875 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Slm8G-0005yn-6M for ged-emacs-devel@m.gmane.org; Mon, 02 Jul 2012 15:18:00 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:37047) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Slm87-0005vq-VI for emacs-devel@gnu.org; Mon, 02 Jul 2012 15:17:58 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Slm83-0000Un-Ep for emacs-devel@gnu.org; Mon, 02 Jul 2012 15:17:51 -0400 Original-Received: from mx1.redhat.com ([209.132.183.28]:33516) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Slm83-0000UI-1J for emacs-devel@gnu.org; Mon, 02 Jul 2012 15:17:47 -0400 Original-Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q62JHkv5004387 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 2 Jul 2012 15:17:46 -0400 Original-Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q62JHcVj026020 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Mon, 2 Jul 2012 15:17:39 -0400 X-Attribution: Tom In-Reply-To: (Stefan Monnier's message of "Sat, 30 Jun 2012 00:07:28 -0400") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:151374 Archived-At: Stefan> Could be, yes. Could you re-post the URL to the latest/cleanest version Stefan> of it? I pulled it from the bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=4470 (btw, gnus-read-ephemeral-emacs-bug-group is awesome) and rebased it. The appended bootstraps for me. No ChangeLog, but I can write one if you are still interested in the patch. I didn't do any performance testing this time around. FWIW I suspect a bigger win would be had by applying this treatment -- or even better, a full threaded interpreter -- to the regexp matcher. Back when I did some profiling of Emacs, the regexp matcher was higher in my profiles than the bytecode interpreter. However, this fact doesn't make this patch less desirable. Tom diff --git a/src/bytecode.c b/src/bytecode.c index 08a02ea..0fe4456 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -54,6 +54,13 @@ by Hallvard: /* #define BYTE_CODE_SAFE */ /* #define BYTE_CODE_METER */ +/* If BYTE_CODE_THREADED is defined, then the interpreter will be + indirect threaded, using GCC's computed goto extension. This is + incompatible with BYTE_CODE_SAFE and BYTE_CODE_METER. */ +#if defined (__GNUC__) && !defined (BYTE_CODE_SAFE) && !defined (BYTE_CODE_METER) +#define BYTE_CODE_THREADED +#endif + #ifdef BYTE_CODE_METER @@ -84,11 +91,53 @@ Lisp_Object Qbytecode; /* Byte codes: */ #define Bstack_ref 0 /* Actually, Bstack_ref+0 is not implemented: use dup. */ +#define Bstack_ref1 1 +#define Bstack_ref2 2 +#define Bstack_ref3 3 +#define Bstack_ref4 4 +#define Bstack_ref5 5 +#define Bstack_ref6 6 +#define Bstack_ref7 7 #define Bvarref 010 +#define Bvarref1 011 +#define Bvarref2 012 +#define Bvarref3 013 +#define Bvarref4 014 +#define Bvarref5 015 +#define Bvarref6 016 +#define Bvarref7 017 #define Bvarset 020 +#define Bvarset1 021 +#define Bvarset2 022 +#define Bvarset3 023 +#define Bvarset4 024 +#define Bvarset5 025 +#define Bvarset6 026 +#define Bvarset7 027 #define Bvarbind 030 +#define Bvarbind1 031 +#define Bvarbind2 032 +#define Bvarbind3 033 +#define Bvarbind4 034 +#define Bvarbind5 035 +#define Bvarbind6 036 +#define Bvarbind7 037 #define Bcall 040 +#define Bcall1 041 +#define Bcall2 042 +#define Bcall3 043 +#define Bcall4 044 +#define Bcall5 045 +#define Bcall6 046 +#define Bcall7 047 #define Bunbind 050 +#define Bunbind1 051 +#define Bunbind2 052 +#define Bunbind3 053 +#define Bunbind4 054 +#define Bunbind5 055 +#define Bunbind6 056 +#define Bunbind7 057 #define Bnth 070 #define Bsymbolp 071 @@ -561,27 +610,249 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, this_op = op = FETCH; METER_CODE (prev_op, op); #else +#ifndef BYTE_CODE_THREADED op = FETCH; #endif +#endif + + /* The interpreter can be compiled one of two ways: as an + ordinary switch-based interpreter, or as a threaded + interpreter. The threaded interpreter relies on GCC's + computed goto extension, so it is not available everywhere. + Threading provides a performance boost. These macros are how + we allow the code to be compiled both ways. */ +#ifdef BYTE_CODE_THREADED + /* The CASE macro introduces an instruction's body. It is + either a label or a case label. */ +#define CASE(OP) insn_ ## OP + /* NEXT is invoked at the end of an instruction to go to the + next instruction. It is either a computed goto, or a + plain break. */ +#define NEXT goto *(targets[op = FETCH]) + /* FIRST is like NEXT, but is only used at the start of the + interpreter body. In the switch-based interpreter it is the + switch, so the threaded definition must include a semicolon. */ +#define FIRST NEXT; + /* Most cases are labeled with the CASE macro, above. + CASE_DEFAULT is one exception; it is used if the interpreter + being built requires a default case. The threaded + interpreter does not, because the dispatch table is + completely filled. */ +#define CASE_DEFAULT + /* This introduces an instruction that is known to call abort. */ +#define CASE_ABORT CASE (default) +#else + /* See above for the meaning of the various defines. */ +#define CASE(OP) case OP +#define NEXT break +#define FIRST switch (op) +#define CASE_DEFAULT case 255: default: +#define CASE_ABORT case 0 +#endif + +#ifdef BYTE_CODE_THREADED + + /* A convenience define that saves us a lot of typing and makes + the table clearer. */ +#define LABEL(OP) [OP] = &&insn_ ## OP + + /* This is the dispatch table for the threaded interpreter. */ + static const void *const targets[256] = + { + [0 ... (Bconstant - 1)] = &&insn_default, + [Bconstant ... 255] = &&insn_Bconstant, + + LABEL (Bstack_ref1), + LABEL (Bstack_ref2), + LABEL (Bstack_ref3), + LABEL (Bstack_ref4), + LABEL (Bstack_ref5), + LABEL (Bstack_ref6), + LABEL (Bstack_ref7), + LABEL (Bvarref), + LABEL (Bvarref1), + LABEL (Bvarref2), + LABEL (Bvarref3), + LABEL (Bvarref4), + LABEL (Bvarref5), + LABEL (Bvarref6), + LABEL (Bvarref7), + LABEL (Bvarset), + LABEL (Bvarset1), + LABEL (Bvarset2), + LABEL (Bvarset3), + LABEL (Bvarset4), + LABEL (Bvarset5), + LABEL (Bvarset6), + LABEL (Bvarset7), + LABEL (Bvarbind), + LABEL (Bvarbind1), + LABEL (Bvarbind2), + LABEL (Bvarbind3), + LABEL (Bvarbind4), + LABEL (Bvarbind5), + LABEL (Bvarbind6), + LABEL (Bvarbind7), + LABEL (Bcall), + LABEL (Bcall1), + LABEL (Bcall2), + LABEL (Bcall3), + LABEL (Bcall4), + LABEL (Bcall5), + LABEL (Bcall6), + LABEL (Bcall7), + LABEL (Bunbind), + LABEL (Bunbind1), + LABEL (Bunbind2), + LABEL (Bunbind3), + LABEL (Bunbind4), + LABEL (Bunbind5), + LABEL (Bunbind6), + LABEL (Bunbind7), + LABEL (Bnth), + LABEL (Bsymbolp), + LABEL (Bconsp), + LABEL (Bstringp), + LABEL (Blistp), + LABEL (Beq), + LABEL (Bmemq), + LABEL (Bnot), + LABEL (Bcar), + LABEL (Bcdr), + LABEL (Bcons), + LABEL (Blist1), + LABEL (Blist2), + LABEL (Blist3), + LABEL (Blist4), + LABEL (Blength), + LABEL (Baref), + LABEL (Baset), + LABEL (Bsymbol_value), + LABEL (Bsymbol_function), + LABEL (Bset), + LABEL (Bfset), + LABEL (Bget), + LABEL (Bsubstring), + LABEL (Bconcat2), + LABEL (Bconcat3), + LABEL (Bconcat4), + LABEL (Bsub1), + LABEL (Badd1), + LABEL (Beqlsign), + LABEL (Bgtr), + LABEL (Blss), + LABEL (Bleq), + LABEL (Bgeq), + LABEL (Bdiff), + LABEL (Bnegate), + LABEL (Bplus), + LABEL (Bmax), + LABEL (Bmin), + LABEL (Bmult), + LABEL (Bpoint), + LABEL (Bsave_current_buffer), + LABEL (Bgoto_char), + LABEL (Binsert), + LABEL (Bpoint_max), + LABEL (Bpoint_min), + LABEL (Bchar_after), + LABEL (Bfollowing_char), + LABEL (Bpreceding_char), + LABEL (Bcurrent_column), + LABEL (Bindent_to), + LABEL (Beolp), + LABEL (Beobp), + LABEL (Bbolp), + LABEL (Bbobp), + LABEL (Bcurrent_buffer), + LABEL (Bset_buffer), + LABEL (Bsave_current_buffer_1), + LABEL (Binteractive_p), + LABEL (Bforward_char), + LABEL (Bforward_word), + LABEL (Bskip_chars_forward), + LABEL (Bskip_chars_backward), + LABEL (Bforward_line), + LABEL (Bchar_syntax), + LABEL (Bbuffer_substring), + LABEL (Bdelete_region), + LABEL (Bnarrow_to_region), + LABEL (Bwiden), + LABEL (Bend_of_line), + LABEL (Bconstant2), + LABEL (Bgoto), + LABEL (Bgotoifnil), + LABEL (Bgotoifnonnil), + LABEL (Bgotoifnilelsepop), + LABEL (Bgotoifnonnilelsepop), + LABEL (Breturn), + LABEL (Bdiscard), + LABEL (Bdup), + LABEL (Bsave_excursion), + LABEL (Bsave_window_excursion), + LABEL (Bsave_restriction), + LABEL (Bcatch), + LABEL (Bunwind_protect), + LABEL (Bcondition_case), + LABEL (Btemp_output_buffer_setup), + LABEL (Btemp_output_buffer_show), + LABEL (Bunbind_all), + LABEL (Bset_marker), + LABEL (Bmatch_beginning), + LABEL (Bmatch_end), + LABEL (Bupcase), + LABEL (Bdowncase), + LABEL (Bstringeqlsign), + LABEL (Bstringlss), + LABEL (Bequal), + LABEL (Bnthcdr), + LABEL (Belt), + LABEL (Bmember), + LABEL (Bassq), + LABEL (Bnreverse), + LABEL (Bsetcar), + LABEL (Bsetcdr), + LABEL (Bcar_safe), + LABEL (Bcdr_safe), + LABEL (Bnconc), + LABEL (Bquo), + LABEL (Brem), + LABEL (Bnumberp), + LABEL (Bintegerp), + LABEL (BRgoto), + LABEL (BRgotoifnil), + LABEL (BRgotoifnonnil), + LABEL (BRgotoifnilelsepop), + LABEL (BRgotoifnonnilelsepop), + LABEL (BlistN), + LABEL (BconcatN), + LABEL (BinsertN), + LABEL (Bstack_set), + LABEL (Bstack_set2), + LABEL (BdiscardN), + LABEL (Bconstant) + }; +#endif + - switch (op) + FIRST { - case Bvarref + 7: + CASE (Bvarref7): op = FETCH2; goto varref; - case Bvarref: - case Bvarref + 1: - case Bvarref + 2: - case Bvarref + 3: - case Bvarref + 4: - case Bvarref + 5: + CASE (Bvarref): + CASE (Bvarref1): + CASE (Bvarref2): + CASE (Bvarref3): + CASE (Bvarref4): + CASE (Bvarref5): op = op - Bvarref; goto varref; /* This seems to be the most frequently executed byte-code among the Bvarref's, so avoid a goto here. */ - case Bvarref+6: + CASE (Bvarref6): op = FETCH; varref: { @@ -606,10 +877,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, AFTER_POTENTIAL_GC (); } PUSH (v2); - break; + NEXT; } - case Bgotoifnil: + CASE (Bgotoifnil): { Lisp_Object v1; MAYBE_GC (); @@ -621,10 +892,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, CHECK_RANGE (op); stack.pc = stack.byte_string_start + op; } - break; + NEXT; } - case Bcar: + CASE (Bcar): { Lisp_Object v1; v1 = TOP; @@ -638,28 +909,28 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, wrong_type_argument (Qlistp, v1); AFTER_POTENTIAL_GC (); } - break; + NEXT; } - case Beq: + CASE (Beq): { Lisp_Object v1; v1 = POP; TOP = EQ (v1, TOP) ? Qt : Qnil; - break; + NEXT; } - case Bmemq: + CASE (Bmemq): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fmemq (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bcdr: + CASE (Bcdr): { Lisp_Object v1; v1 = TOP; @@ -673,24 +944,23 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, wrong_type_argument (Qlistp, v1); AFTER_POTENTIAL_GC (); } - break; - break; + NEXT; } - case Bvarset: - case Bvarset+1: - case Bvarset+2: - case Bvarset+3: - case Bvarset+4: - case Bvarset+5: + CASE (Bvarset): + CASE (Bvarset1): + CASE (Bvarset2): + CASE (Bvarset3): + CASE (Bvarset4): + CASE (Bvarset5): op -= Bvarset; goto varset; - case Bvarset+7: + CASE (Bvarset7): op = FETCH2; goto varset; - case Bvarset+6: + CASE (Bvarset6): op = FETCH; varset: { @@ -713,54 +983,54 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, } } (void) POP; - break; + NEXT; - case Bdup: + CASE (Bdup): { Lisp_Object v1; v1 = TOP; PUSH (v1); - break; + NEXT; } /* ------------------ */ - case Bvarbind+6: + CASE (Bvarbind6): op = FETCH; goto varbind; - case Bvarbind+7: + CASE (Bvarbind7): op = FETCH2; goto varbind; - case Bvarbind: - case Bvarbind+1: - case Bvarbind+2: - case Bvarbind+3: - case Bvarbind+4: - case Bvarbind+5: + CASE (Bvarbind): + CASE (Bvarbind1): + CASE (Bvarbind2): + CASE (Bvarbind3): + CASE (Bvarbind4): + CASE (Bvarbind5): op -= Bvarbind; varbind: /* Specbind can signal and thus GC. */ BEFORE_POTENTIAL_GC (); specbind (vectorp[op], POP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bcall+6: + CASE (Bcall6): op = FETCH; goto docall; - case Bcall+7: + CASE (Bcall7): op = FETCH2; goto docall; - case Bcall: - case Bcall+1: - case Bcall+2: - case Bcall+3: - case Bcall+4: - case Bcall+5: + CASE (Bcall): + CASE (Bcall1): + CASE (Bcall2): + CASE (Bcall3): + CASE (Bcall4): + CASE (Bcall5): op -= Bcall; docall: { @@ -783,47 +1053,47 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, #endif TOP = Ffuncall (op + 1, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bunbind+6: + CASE (Bunbind6): op = FETCH; goto dounbind; - case Bunbind+7: + CASE (Bunbind7): op = FETCH2; goto dounbind; - case Bunbind: - case Bunbind+1: - case Bunbind+2: - case Bunbind+3: - case Bunbind+4: - case Bunbind+5: + CASE (Bunbind): + CASE (Bunbind1): + CASE (Bunbind2): + CASE (Bunbind3): + CASE (Bunbind4): + CASE (Bunbind5): op -= Bunbind; dounbind: BEFORE_POTENTIAL_GC (); unbind_to (SPECPDL_INDEX () - op, Qnil); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bunbind_all: /* Obsolete. Never used. */ + CASE (Bunbind_all): /* Obsolete. Never used. */ /* To unbind back to the beginning of this frame. Not used yet, but will be needed for tail-recursion elimination. */ BEFORE_POTENTIAL_GC (); unbind_to (count, Qnil); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bgoto: + CASE (Bgoto): MAYBE_GC (); BYTE_CODE_QUIT; op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ CHECK_RANGE (op); stack.pc = stack.byte_string_start + op; - break; + NEXT; - case Bgotoifnonnil: + CASE (Bgotoifnonnil): { Lisp_Object v1; MAYBE_GC (); @@ -835,10 +1105,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, CHECK_RANGE (op); stack.pc = stack.byte_string_start + op; } - break; + NEXT; } - case Bgotoifnilelsepop: + CASE (Bgotoifnilelsepop): MAYBE_GC (); op = FETCH2; if (NILP (TOP)) @@ -848,9 +1118,9 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, stack.pc = stack.byte_string_start + op; } else DISCARD (1); - break; + NEXT; - case Bgotoifnonnilelsepop: + CASE (Bgotoifnonnilelsepop): MAYBE_GC (); op = FETCH2; if (!NILP (TOP)) @@ -860,15 +1130,15 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, stack.pc = stack.byte_string_start + op; } else DISCARD (1); - break; + NEXT; - case BRgoto: + CASE (BRgoto): MAYBE_GC (); BYTE_CODE_QUIT; stack.pc += (int) *stack.pc - 127; - break; + NEXT; - case BRgotoifnil: + CASE (BRgotoifnil): { Lisp_Object v1; MAYBE_GC (); @@ -879,10 +1149,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, stack.pc += (int) *stack.pc - 128; } stack.pc++; - break; + NEXT; } - case BRgotoifnonnil: + CASE (BRgotoifnonnil): { Lisp_Object v1; MAYBE_GC (); @@ -893,10 +1163,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, stack.pc += (int) *stack.pc - 128; } stack.pc++; - break; + NEXT; } - case BRgotoifnilelsepop: + CASE (BRgotoifnilelsepop): MAYBE_GC (); op = *stack.pc++; if (NILP (TOP)) @@ -905,9 +1175,9 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, stack.pc += op - 128; } else DISCARD (1); - break; + NEXT; - case BRgotoifnonnilelsepop: + CASE (BRgotoifnonnilelsepop): MAYBE_GC (); op = *stack.pc++; if (!NILP (TOP)) @@ -916,31 +1186,31 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, stack.pc += op - 128; } else DISCARD (1); - break; + NEXT; - case Breturn: + CASE (Breturn): result = POP; goto exit; - case Bdiscard: + CASE (Bdiscard): DISCARD (1); - break; + NEXT; - case Bconstant2: + CASE (Bconstant2): PUSH (vectorp[FETCH2]); - break; + NEXT; - case Bsave_excursion: + CASE (Bsave_excursion): record_unwind_protect (save_excursion_restore, save_excursion_save ()); - break; + NEXT; - case Bsave_current_buffer: /* Obsolete since ??. */ - case Bsave_current_buffer_1: + CASE (Bsave_current_buffer): /* Obsolete since ??. */ + CASE (Bsave_current_buffer_1): record_unwind_protect (set_buffer_if_live, Fcurrent_buffer ()); - break; + NEXT; - case Bsave_window_excursion: /* Obsolete since 24.1. */ + CASE (Bsave_window_excursion): /* Obsolete since 24.1. */ { register ptrdiff_t count1 = SPECPDL_INDEX (); record_unwind_protect (Fset_window_configuration, @@ -949,29 +1219,29 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, TOP = Fprogn (TOP); unbind_to (count1, TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bsave_restriction: + CASE (Bsave_restriction): record_unwind_protect (save_restriction_restore, save_restriction_save ()); - break; + NEXT; - case Bcatch: /* FIXME: ill-suited for lexbind. */ + CASE (Bcatch): /* FIXME: ill-suited for lexbind. */ { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = internal_catch (TOP, eval_sub, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bunwind_protect: /* FIXME: avoid closure for lexbind. */ + CASE (Bunwind_protect): /* FIXME: avoid closure for lexbind. */ record_unwind_protect (Fprogn, POP); - break; + NEXT; - case Bcondition_case: /* FIXME: ill-suited for lexbind. */ + CASE (Bcondition_case): /* FIXME: ill-suited for lexbind. */ { Lisp_Object handlers, body; handlers = POP; @@ -979,18 +1249,18 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, BEFORE_POTENTIAL_GC (); TOP = internal_lisp_condition_case (TOP, body, handlers); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Btemp_output_buffer_setup: /* Obsolete since 24.1. */ + CASE (Btemp_output_buffer_setup): /* Obsolete since 24.1. */ BEFORE_POTENTIAL_GC (); CHECK_STRING (TOP); temp_output_buffer_setup (SSDATA (TOP)); AFTER_POTENTIAL_GC (); TOP = Vstandard_output; - break; + NEXT; - case Btemp_output_buffer_show: /* Obsolete since 24.1. */ + CASE (Btemp_output_buffer_show): /* Obsolete since 24.1. */ { Lisp_Object v1; BEFORE_POTENTIAL_GC (); @@ -1000,10 +1270,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, /* pop binding of standard-output */ unbind_to (SPECPDL_INDEX () - 1, Qnil); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bnth: + CASE (Bnth): { Lisp_Object v1, v2; EMACS_INT n; @@ -1018,173 +1288,173 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, immediate_quit = 0; TOP = CAR (v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bsymbolp: + CASE (Bsymbolp): TOP = SYMBOLP (TOP) ? Qt : Qnil; - break; + NEXT; - case Bconsp: + CASE (Bconsp): TOP = CONSP (TOP) ? Qt : Qnil; - break; + NEXT; - case Bstringp: + CASE (Bstringp): TOP = STRINGP (TOP) ? Qt : Qnil; - break; + NEXT; - case Blistp: + CASE (Blistp): TOP = CONSP (TOP) || NILP (TOP) ? Qt : Qnil; - break; + NEXT; - case Bnot: + CASE (Bnot): TOP = NILP (TOP) ? Qt : Qnil; - break; + NEXT; - case Bcons: + CASE (Bcons): { Lisp_Object v1; v1 = POP; TOP = Fcons (TOP, v1); - break; + NEXT; } - case Blist1: + CASE (Blist1): TOP = Fcons (TOP, Qnil); - break; + NEXT; - case Blist2: + CASE (Blist2): { Lisp_Object v1; v1 = POP; TOP = Fcons (TOP, Fcons (v1, Qnil)); - break; + NEXT; } - case Blist3: + CASE (Blist3): DISCARD (2); TOP = Flist (3, &TOP); - break; + NEXT; - case Blist4: + CASE (Blist4): DISCARD (3); TOP = Flist (4, &TOP); - break; + NEXT; - case BlistN: + CASE (BlistN): op = FETCH; DISCARD (op - 1); TOP = Flist (op, &TOP); - break; + NEXT; - case Blength: + CASE (Blength): BEFORE_POTENTIAL_GC (); TOP = Flength (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Baref: + CASE (Baref): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Faref (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Baset: + CASE (Baset): { Lisp_Object v1, v2; BEFORE_POTENTIAL_GC (); v2 = POP; v1 = POP; TOP = Faset (TOP, v1, v2); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bsymbol_value: + CASE (Bsymbol_value): BEFORE_POTENTIAL_GC (); TOP = Fsymbol_value (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bsymbol_function: + CASE (Bsymbol_function): BEFORE_POTENTIAL_GC (); TOP = Fsymbol_function (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bset: + CASE (Bset): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fset (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bfset: + CASE (Bfset): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Ffset (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bget: + CASE (Bget): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fget (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bsubstring: + CASE (Bsubstring): { Lisp_Object v1, v2; BEFORE_POTENTIAL_GC (); v2 = POP; v1 = POP; TOP = Fsubstring (TOP, v1, v2); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bconcat2: + CASE (Bconcat2): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fconcat (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bconcat3: + CASE (Bconcat3): BEFORE_POTENTIAL_GC (); DISCARD (2); TOP = Fconcat (3, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bconcat4: + CASE (Bconcat4): BEFORE_POTENTIAL_GC (); DISCARD (3); TOP = Fconcat (4, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case BconcatN: + CASE (BconcatN): op = FETCH; BEFORE_POTENTIAL_GC (); DISCARD (op - 1); TOP = Fconcat (op, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bsub1: + CASE (Bsub1): { Lisp_Object v1; v1 = TOP; @@ -1199,10 +1469,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, TOP = Fsub1 (v1); AFTER_POTENTIAL_GC (); } - break; + NEXT; } - case Badd1: + CASE (Badd1): { Lisp_Object v1; v1 = TOP; @@ -1217,10 +1487,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, TOP = Fadd1 (v1); AFTER_POTENTIAL_GC (); } - break; + NEXT; } - case Beqlsign: + CASE (Beqlsign): { Lisp_Object v1, v2; BEFORE_POTENTIAL_GC (); @@ -1238,57 +1508,57 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, } else TOP = (XINT (v1) == XINT (v2) ? Qt : Qnil); - break; + NEXT; } - case Bgtr: + CASE (Bgtr): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fgtr (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Blss: + CASE (Blss): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Flss (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bleq: + CASE (Bleq): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fleq (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bgeq: + CASE (Bgeq): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fgeq (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bdiff: + CASE (Bdiff): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fminus (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bnegate: + CASE (Bnegate): { Lisp_Object v1; v1 = TOP; @@ -1303,209 +1573,209 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, TOP = Fminus (1, &TOP); AFTER_POTENTIAL_GC (); } - break; + NEXT; } - case Bplus: + CASE (Bplus): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fplus (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bmax: + CASE (Bmax): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fmax (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bmin: + CASE (Bmin): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fmin (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bmult: + CASE (Bmult): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Ftimes (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bquo: + CASE (Bquo): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fquo (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Brem: + CASE (Brem): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Frem (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bpoint: + CASE (Bpoint): { Lisp_Object v1; XSETFASTINT (v1, PT); PUSH (v1); - break; + NEXT; } - case Bgoto_char: + CASE (Bgoto_char): BEFORE_POTENTIAL_GC (); TOP = Fgoto_char (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Binsert: + CASE (Binsert): BEFORE_POTENTIAL_GC (); TOP = Finsert (1, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case BinsertN: + CASE (BinsertN): op = FETCH; BEFORE_POTENTIAL_GC (); DISCARD (op - 1); TOP = Finsert (op, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bpoint_max: + CASE (Bpoint_max): { Lisp_Object v1; XSETFASTINT (v1, ZV); PUSH (v1); - break; + NEXT; } - case Bpoint_min: + CASE (Bpoint_min): { Lisp_Object v1; XSETFASTINT (v1, BEGV); PUSH (v1); - break; + NEXT; } - case Bchar_after: + CASE (Bchar_after): BEFORE_POTENTIAL_GC (); TOP = Fchar_after (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bfollowing_char: + CASE (Bfollowing_char): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = Ffollowing_char (); AFTER_POTENTIAL_GC (); PUSH (v1); - break; + NEXT; } - case Bpreceding_char: + CASE (Bpreceding_char): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = Fprevious_char (); AFTER_POTENTIAL_GC (); PUSH (v1); - break; + NEXT; } - case Bcurrent_column: + CASE (Bcurrent_column): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); XSETFASTINT (v1, current_column ()); AFTER_POTENTIAL_GC (); PUSH (v1); - break; + NEXT; } - case Bindent_to: + CASE (Bindent_to): BEFORE_POTENTIAL_GC (); TOP = Findent_to (TOP, Qnil); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Beolp: + CASE (Beolp): PUSH (Feolp ()); - break; + NEXT; - case Beobp: + CASE (Beobp): PUSH (Feobp ()); - break; + NEXT; - case Bbolp: + CASE (Bbolp): PUSH (Fbolp ()); - break; + NEXT; - case Bbobp: + CASE (Bbobp): PUSH (Fbobp ()); - break; + NEXT; - case Bcurrent_buffer: + CASE (Bcurrent_buffer): PUSH (Fcurrent_buffer ()); - break; + NEXT; - case Bset_buffer: + CASE (Bset_buffer): BEFORE_POTENTIAL_GC (); TOP = Fset_buffer (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Binteractive_p: /* Obsolete since 24.1. */ + CASE (Binteractive_p): /* Obsolete since 24.1. */ PUSH (Finteractive_p ()); - break; + NEXT; - case Bforward_char: + CASE (Bforward_char): BEFORE_POTENTIAL_GC (); TOP = Fforward_char (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bforward_word: + CASE (Bforward_word): BEFORE_POTENTIAL_GC (); TOP = Fforward_word (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bskip_chars_forward: + CASE (Bskip_chars_forward): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fskip_chars_forward (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bskip_chars_backward: + CASE (Bskip_chars_backward): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fskip_chars_backward (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bforward_line: + CASE (Bforward_line): BEFORE_POTENTIAL_GC (); TOP = Fforward_line (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bchar_syntax: + CASE (Bchar_syntax): { int c; @@ -1517,51 +1787,51 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, MAKE_CHAR_MULTIBYTE (c); XSETFASTINT (TOP, syntax_code_spec[(int) SYNTAX (c)]); } - break; + NEXT; - case Bbuffer_substring: + CASE (Bbuffer_substring): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fbuffer_substring (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bdelete_region: + CASE (Bdelete_region): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fdelete_region (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bnarrow_to_region: + CASE (Bnarrow_to_region): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fnarrow_to_region (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bwiden: + CASE (Bwiden): BEFORE_POTENTIAL_GC (); PUSH (Fwiden ()); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bend_of_line: + CASE (Bend_of_line): BEFORE_POTENTIAL_GC (); TOP = Fend_of_line (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bset_marker: + CASE (Bset_marker): { Lisp_Object v1, v2; BEFORE_POTENTIAL_GC (); @@ -1569,72 +1839,72 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, v2 = POP; TOP = Fset_marker (TOP, v2, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bmatch_beginning: + CASE (Bmatch_beginning): BEFORE_POTENTIAL_GC (); TOP = Fmatch_beginning (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bmatch_end: + CASE (Bmatch_end): BEFORE_POTENTIAL_GC (); TOP = Fmatch_end (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bupcase: + CASE (Bupcase): BEFORE_POTENTIAL_GC (); TOP = Fupcase (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bdowncase: + CASE (Bdowncase): BEFORE_POTENTIAL_GC (); TOP = Fdowncase (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bstringeqlsign: + CASE (Bstringeqlsign): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fstring_equal (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bstringlss: + CASE (Bstringlss): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fstring_lessp (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bequal: + CASE (Bequal): { Lisp_Object v1; v1 = POP; TOP = Fequal (TOP, v1); - break; + NEXT; } - case Bnthcdr: + CASE (Bnthcdr): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fnthcdr (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Belt: + CASE (Belt): { Lisp_Object v1, v2; if (CONSP (TOP)) @@ -1660,87 +1930,91 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, TOP = Felt (TOP, v1); AFTER_POTENTIAL_GC (); } - break; + NEXT; } - case Bmember: + CASE (Bmember): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fmember (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bassq: + CASE (Bassq): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fassq (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bnreverse: + CASE (Bnreverse): BEFORE_POTENTIAL_GC (); TOP = Fnreverse (TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bsetcar: + CASE (Bsetcar): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fsetcar (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bsetcdr: + CASE (Bsetcdr): { Lisp_Object v1; BEFORE_POTENTIAL_GC (); v1 = POP; TOP = Fsetcdr (TOP, v1); AFTER_POTENTIAL_GC (); - break; + NEXT; } - case Bcar_safe: + CASE (Bcar_safe): { Lisp_Object v1; v1 = TOP; TOP = CAR_SAFE (v1); - break; + NEXT; } - case Bcdr_safe: + CASE (Bcdr_safe): { Lisp_Object v1; v1 = TOP; TOP = CDR_SAFE (v1); - break; + NEXT; } - case Bnconc: + CASE (Bnconc): BEFORE_POTENTIAL_GC (); DISCARD (1); TOP = Fnconc (2, &TOP); AFTER_POTENTIAL_GC (); - break; + NEXT; - case Bnumberp: + CASE (Bnumberp): TOP = (NUMBERP (TOP) ? Qt : Qnil); - break; + NEXT; - case Bintegerp: + CASE (Bintegerp): TOP = INTEGERP (TOP) ? Qt : Qnil; - break; + NEXT; #ifdef BYTE_CODE_SAFE + /* These are intentionally written using 'case' syntax, + because they are incompatible with the threaded + interpreter. */ + case Bset_mark: BEFORE_POTENTIAL_GC (); error ("set-mark is an obsolete bytecode"); @@ -1753,49 +2027,49 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, break; #endif - case 0: + CASE_ABORT: /* Actually this is Bstack_ref with offset 0, but we use Bdup for that instead. */ - /* case Bstack_ref: */ + /* CASE (Bstack_ref): */ abort (); /* Handy byte-codes for lexical binding. */ - case Bstack_ref+1: - case Bstack_ref+2: - case Bstack_ref+3: - case Bstack_ref+4: - case Bstack_ref+5: + CASE (Bstack_ref1): + CASE (Bstack_ref2): + CASE (Bstack_ref3): + CASE (Bstack_ref4): + CASE (Bstack_ref5): { Lisp_Object *ptr = top - (op - Bstack_ref); PUSH (*ptr); - break; + NEXT; } - case Bstack_ref+6: + CASE (Bstack_ref6): { Lisp_Object *ptr = top - (FETCH); PUSH (*ptr); - break; + NEXT; } - case Bstack_ref+7: + CASE (Bstack_ref7): { Lisp_Object *ptr = top - (FETCH2); PUSH (*ptr); - break; + NEXT; } - case Bstack_set: + CASE (Bstack_set): /* stack-set-0 = discard; stack-set-1 = discard-1-preserve-tos. */ { Lisp_Object *ptr = top - (FETCH); *ptr = POP; - break; + NEXT; } - case Bstack_set2: + CASE (Bstack_set2): { Lisp_Object *ptr = top - (FETCH2); *ptr = POP; - break; + NEXT; } - case BdiscardN: + CASE (BdiscardN): op = FETCH; if (op & 0x80) { @@ -1803,10 +2077,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, top[-op] = TOP; } DISCARD (op); - break; + NEXT; - case 255: - default: + CASE_DEFAULT + CASE (Bconstant): #ifdef BYTE_CODE_SAFE if (op < Bconstant) { @@ -1820,6 +2094,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, #else PUSH (vectorp[op - Bconstant]); #endif + NEXT; } }