[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] nick.lloyd-bytecode-jit e0b099f 2/9: Add bytecode JIT comp
From: |
Nickolas Lloyd |
Subject: |
[Emacs-diffs] nick.lloyd-bytecode-jit e0b099f 2/9: Add bytecode JIT compilation capabilities |
Date: |
Fri, 23 Dec 2016 16:33:37 +0000 (UTC) |
branch: nick.lloyd-bytecode-jit
commit e0b099f10d916396fc638c25c847ad82e500df69
Author: Nickolas Lloyd <address@hidden>
Commit: Nickolas Lloyd <address@hidden>
Add bytecode JIT compilation capabilities
This change adds several functions that utilize GNU libjit to compile
byte-compiled lisp functions to machine code. The functionality is exposed
in two ways: specific functions can be JIT compiled from lisp with the
`jit-compile' function, or JIT compilation can be enabled globally by
setting
`byte-code-jit-on' to non-nil. Once the function has been JIT compiled, the
machine-code version will be executed in place of the bytecode version.
* src/bytecode-jit.c (native_varref, native_ifnil, native_ifnonnil)
(native_car, native_eq, native_memq, native_cdr, native_varset)
(native_unbind_to, byte_code_quit, native_save_excursion)
(native_save_restriction, native_save_window_excursion, native_catch)
(native_pophandler, native_pushhandler1, native_pushhandler2)
(native_unwind_protect, native_temp_output_buffer_setup, native_nth)
(native_symbolp, native_consp, native_stringp, native_listp, native_not)
(native_add1, native_eqlsign, native_negate, native_point, native_point_max)
(native_point_min, native_current_column, native_interactive_p)
(native_char_syntax, native_elt, native_car_safe, native_cdr_safe)
(native_number_p, native_integer_p, emacs_jit_init, jit_exec,
jit_byte_code__)
(jit_byte_code, Fjit_compile, syms_of_bytecode_jit): New file encapsulating
JIT compilation functionality and execution functionality.
* src/bytecode.c:
* src/bytecode.h: Extract useful data structures and macro definitions into
a
separate header to allow sharing between src/bytecode{,-jit}.c.
; * src/Makefile.in: Add src/bytecode-jit.o to Makefile recipe.
; * src/lisp.h: Add function prototypes for new JIT functions.
; * src/emacs.c: Call syms_of_bytecode_jit to initialize JIT-related
symbols.
---
configure.ac | 13 +
src/Makefile.in | 8 +-
src/bytecode-jit.c | 2131 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/bytecode.c | 282 +------
src/bytecode.h | 283 +++++++
src/data.c | 1 +
src/emacs.c | 1 +
src/eval.c | 12 +-
src/lisp.h | 10 +
9 files changed, 2451 insertions(+), 290 deletions(-)
diff --git a/configure.ac b/configure.ac
index cd4d1c0..114e92d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -354,6 +354,7 @@ OPTION_DEFAULT_ON([selinux],[don't compile with SELinux
support])
OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
OPTION_DEFAULT_ON([zlib],[don't compile with zlib decompression support])
OPTION_DEFAULT_OFF([modules],[compile with dynamic modules support])
+OPTION_DEFAULT_ON([libjit],[compile with emacs lisp jit support])
AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
[use a file notification library (LIB one of: yes, inotify, kqueue, gfile,
w32, no)])],
@@ -3350,6 +3351,18 @@ if test "${HAVE_ZLIB}" = "yes"; then
fi
AC_SUBST(LIBZ)
+HAVE_LIBJIT=no
+LIBJIT=
+if test "${with_libjit}" != "no"; then
+ OLIBS=$LIBS
+ LIBJIT_REQUIRED=0.0.1
+ LIBJIT_MODULES="libjit >= $LIBJIT_REQUIRED"
+ EMACS_CHECK_MODULES([LIBJIT], [$LIBJIT_MODULES])
+ if test "${HAVE_LIBJIT}" = "yes"; then
+ AC_DEFINE([HAVE_LIBJIT], 1, [Define to 1 if you have the libjit library
(-ljit).])
+ fi
+fi
+
### Dynamic modules support
LIBMODULES=
HAVE_MODULES=no
diff --git a/src/Makefile.in b/src/Makefile.in
index d546709..4ae8ae6 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -238,6 +238,9 @@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
LIBZ = @LIBZ@
+LIBJIT = @LIBJIT_LIBS@
+LIBJIT_CFLAGS = @LIBJIT_CFLAGS@
+
## system-specific libs for dynamic modules, else empty
LIBMODULES = @LIBMODULES@
## dynlib.o emacs-module.o if modules enabled, else empty
@@ -370,6 +373,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
$(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
+ $(LIBJIT_CFLAGS) \
$(WARN_CFLAGS) $(WERROR_CFLAGS) $(CFLAGS)
ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
@@ -392,7 +396,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o
$(XMENU_OBJ) window.o \
cmds.o casetab.o casefiddle.o indent.o search.o regex.o undo.o \
alloc.o data.o doc.o editfns.o callint.o \
eval.o floatfns.o fns.o font.o print.o lread.o $(MODULES_OBJ) \
- syntax.o $(UNEXEC_OBJ) bytecode.o \
+ syntax.o $(UNEXEC_OBJ) bytecode.o bytecode-jit.o \
process.o gnutls.o callproc.o \
region-cache.o sound.o atimer.o \
doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \
@@ -484,7 +488,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE)
$(LIBIMAGE) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) \
- $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES)
+ $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBJIT) $(LIBMODULES)
$(leimdir)/leim-list.el: bootstrap-emacs$(EXEEXT)
$(MAKE) -C ../leim leim-list.el EMACS="$(bootstrap_exe)"
diff --git a/src/bytecode-jit.c b/src/bytecode-jit.c
new file mode 100644
index 0000000..3860ade
--- /dev/null
+++ b/src/bytecode-jit.c
@@ -0,0 +1,2131 @@
+/* JIT compilation of byte code produced by bytecomp.el.
+ Copyright (C) 1985-1988, 1993, 2000-2016 Free Software Foundation,
+ Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "bytecode.h"
+#include "lisp.h"
+#include "blockinput.h"
+#include "character.h"
+#include "buffer.h"
+#include "keyboard.h"
+#include "syntax.h"
+#include "window.h"
+
+#include <jit.h>
+
+#ifdef CHECK_FRAME_FONT
+#include "frame.h"
+#include "xterm.h"
+#endif
+
+/* Fetch the next byte from the bytecode stream. */
+
+#ifdef BYTE_CODE_SAFE
+#define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)),
*stack.pc++)
+#else
+#define FETCH *stack.pc++
+#endif
+
+/* Fetch two bytes from the bytecode stream and make a 16-bit number
+ out of them. */
+
+#define FETCH2 (op = FETCH, op + (FETCH << 8))
+
+/* Push x onto the execution stack. This used to be #define PUSH(x)
+ (*++stackp = (x)) This oddity is necessary because Alliant can't be
+ bothered to compile the preincrement operator properly, as of 4/91.
+ -JimB */
+
+#define PUSH(x) (top++, *top = (x))
+
+/* Pop a value off the execution stack. */
+
+#define POP (*top--)
+
+/* Discard n values from the execution stack. */
+
+#define DISCARD(n) (top -= (n))
+
+/* Get the value which is at the top of the execution stack, but don't
+ pop it. */
+
+#define TOP (*top)
+
+#undef BEFORE_POTENTIAL_GC
+#undef AFTER_POTENTIAL_GC
+#define BEFORE_POTENTIAL_GC() ((void )0)
+#define AFTER_POTENTIAL_GC() ((void )0)
+
+/* Check for jumping out of range. */
+
+#ifdef BYTE_CODE_SAFE
+
+#define CHECK_RANGE(ARG) \
+ if (ARG >= bytestr_length) emacs_abort ()
+
+#else /* not BYTE_CODE_SAFE */
+
+#define CHECK_RANGE(ARG)
+
+#endif /* not BYTE_CODE_SAFE */
+
+/* A version of the QUIT macro which makes sure that the stack top is
+ set before signaling `quit'. */
+
+#define BYTE_CODE_QUIT \
+ do { \
+ if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \
+ { \
+ Lisp_Object flag = Vquit_flag; \
+ Vquit_flag = Qnil; \
+ BEFORE_POTENTIAL_GC (); \
+ if (EQ (Vthrow_on_input, flag)) \
+ Fthrow (Vthrow_on_input, Qt); \
+ Fsignal (Qquit, Qnil); \
+ AFTER_POTENTIAL_GC (); \
+ } \
+ else if (pending_signals) \
+ process_pending_signals (); \
+ } while (0)
+
+/* Global jit context */
+jit_context_t jit_context = NULL;
+
+#define jit_type_Lisp_Object jit_type_nuint
+
+jit_type_t native_varref_sig;
+static Lisp_Object
+native_varref (Lisp_Object v1)
+{
+ Lisp_Object v2;
+
+ if (SYMBOLP (v1))
+ {
+ if (XSYMBOL (v1)->redirect != SYMBOL_PLAINVAL
+ || (v2 = SYMBOL_VAL (XSYMBOL (v1)),
+ EQ (v2, Qunbound)))
+ {
+ v2 = Fsymbol_value (v1);
+ }
+ }
+ else
+ {
+ v2 = Fsymbol_value (v1);
+ }
+ return v2;
+}
+
+jit_type_t native_ifnil_sig;
+static bool
+native_ifnil (Lisp_Object v1)
+{
+ maybe_gc ();
+ if (NILP (v1))
+ {
+ BYTE_CODE_QUIT;
+ return true;
+ }
+ else
+ return false;
+}
+
+jit_type_t native_ifnonnil_sig;
+static bool
+native_ifnonnil (Lisp_Object v1)
+{
+ maybe_gc ();
+ if (!NILP (v1))
+ {
+ BYTE_CODE_QUIT;
+ return true;
+ }
+ else
+ return false;
+
+}
+
+jit_type_t native_car_sig;
+static Lisp_Object
+native_car (Lisp_Object v1)
+{
+ if (CONSP (v1))
+ return XCAR (v1);
+ else if (NILP (v1))
+ return Qnil;
+ else
+ {
+ wrong_type_argument (Qlistp, v1);
+ }
+}
+
+jit_type_t native_eq_sig;
+static Lisp_Object
+native_eq (Lisp_Object v1, Lisp_Object v2)
+{
+ return EQ (v1, v2) ? Qt : Qnil;
+}
+
+jit_type_t native_memq_sig;
+static Lisp_Object
+native_memq (Lisp_Object v1, Lisp_Object v2)
+{
+ v1 = Fmemq (v1, v2);
+ return v1;
+}
+
+jit_type_t native_cdr_sig;
+static Lisp_Object
+native_cdr (Lisp_Object v1)
+{
+ if (CONSP (v1))
+ return XCDR (v1);
+ else if (NILP (v1))
+ return Qnil;
+ else
+ {
+ wrong_type_argument (Qlistp, v1);
+ }
+}
+
+jit_type_t native_varset_sig;
+static void
+native_varset (Lisp_Object sym, Lisp_Object val)
+{
+ /* Inline the most common case. */
+ if (SYMBOLP (sym)
+ && !EQ (val, Qunbound)
+ && !XSYMBOL (sym)->redirect
+ && !SYMBOL_CONSTANT_P (sym))
+ SET_SYMBOL_VAL (XSYMBOL (sym), val);
+ else
+ {
+ set_internal (sym, val, Qnil, 0);
+ }
+}
+
+jit_type_t specbind_sig;
+jit_type_t Ffuncall_sig;
+
+jit_type_t native_unbind_to_sig;
+static Lisp_Object
+native_unbind_to (ptrdiff_t x, Lisp_Object q)
+{
+ return unbind_to (SPECPDL_INDEX () - x, q);
+}
+
+jit_type_t unbind_to_sig;
+
+jit_type_t byte_code_quit_sig;
+static void
+byte_code_quit (void)
+{
+ maybe_gc ();
+ BYTE_CODE_QUIT;
+}
+
+jit_type_t native_save_excursion_sig;
+static void
+native_save_excursion (void)
+{
+ record_unwind_protect (save_excursion_restore,
+ save_excursion_save ());
+}
+
+jit_type_t native_save_restriction_sig;
+static void
+native_save_restriction (void)
+{
+ record_unwind_protect (save_restriction_restore,
+ save_restriction_save ());
+}
+
+
+jit_type_t native_save_window_excursion_sig;
+static Lisp_Object
+native_save_window_excursion (Lisp_Object v1)
+{
+ ptrdiff_t count1 = SPECPDL_INDEX ();
+ record_unwind_protect (restore_window_configuration,
+ Fcurrent_window_configuration (Qnil));
+ v1 = Fprogn (v1);
+ unbind_to (count1, v1);
+ return v1;
+}
+
+jit_type_t native_catch_sig;
+static Lisp_Object
+native_catch (Lisp_Object v2, Lisp_Object v1)
+{
+ return internal_catch (v2, eval_sub, v1);
+}
+
+jit_type_t native_pophandler_sig;
+static void
+native_pophandler (void)
+{
+ handlerlist = handlerlist->next;
+}
+
+jit_type_t native_pushhandler1_sig;
+static void *
+native_pushhandler1 (Lisp_Object **stack, Lisp_Object tag,
+ int type)
+{
+ struct handler *c = push_handler (tag, type);
+ c->stack = *stack;
+ return c->jmp;
+}
+
+jit_type_t native_pushhandler2_sig;
+static void
+native_pushhandler2 (Lisp_Object **stack)
+{
+ struct handler *c = handlerlist;
+ native_pophandler ();
+ *stack = c->stack;
+ (*stack)++;
+ **stack = c->val;
+}
+
+jit_type_t native_unwind_protect_sig;
+static void
+native_unwind_protect (Lisp_Object handler)
+{
+ record_unwind_protect (NILP (Ffunctionp (handler))
+ ? unwind_body : bcall0,
+ handler);
+}
+
+jit_type_t native_temp_output_buffer_setup_sig;
+static Lisp_Object
+native_temp_output_buffer_setup (Lisp_Object x)
+{
+ CHECK_STRING (x);
+ temp_output_buffer_setup (SSDATA (x));
+ return Vstandard_output;
+}
+
+jit_type_t native_nth_sig;
+static Lisp_Object
+native_nth (Lisp_Object v1, Lisp_Object v2)
+{
+ EMACS_INT n;
+ CHECK_NUMBER (v1);
+ n = XINT (v1);
+ immediate_quit = 1;
+ while (--n >= 0 && CONSP (v2))
+ v2 = XCDR (v2);
+ immediate_quit = 0;
+ return CAR (v2);
+}
+
+jit_type_t native_symbolp_sig;
+jit_type_t native_consp_sig;
+jit_type_t native_stringp_sig;
+jit_type_t native_listp_sig;
+jit_type_t native_not_sig;
+static Lisp_Object
+native_symbolp (Lisp_Object v1)
+{
+ return SYMBOLP (v1) ? Qt : Qnil;
+}
+static Lisp_Object
+native_consp (Lisp_Object v1)
+{
+ return CONSP (v1) ? Qt : Qnil;
+}
+static Lisp_Object
+native_stringp (Lisp_Object v1)
+{
+ return STRINGP (v1) ? Qt : Qnil;
+}
+static Lisp_Object
+native_listp (Lisp_Object v1)
+{
+ return CONSP (v1) || NILP (v1) ? Qt : Qnil;
+}
+static Lisp_Object
+native_not (Lisp_Object v1)
+{
+ return NILP (v1) ? Qt : Qnil;
+}
+
+jit_type_t native_add1_sig;
+static Lisp_Object
+native_add1 (Lisp_Object v1, bool add)
+{
+ if (INTEGERP (v1))
+ {
+ XSETINT (v1, XINT (v1) + (add ? 1 : -1));
+ return v1;
+ }
+ else if (add)
+ return Fadd1 (v1);
+ else
+ return Fsub1 (v1);
+}
+
+jit_type_t native_eqlsign_sig;
+static Lisp_Object
+native_eqlsign (Lisp_Object v1, Lisp_Object v2)
+{
+ CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1);
+ CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2);
+ if (FLOATP (v1) || FLOATP (v2))
+ {
+ double f1, f2;
+
+ f1 = (FLOATP (v1) ? XFLOAT_DATA (v1) : XINT (v1));
+ f2 = (FLOATP (v2) ? XFLOAT_DATA (v2) : XINT (v2));
+ return (f1 == f2 ? Qt : Qnil);
+ }
+ else
+ return (XINT (v1) == XINT (v2) ? Qt : Qnil);
+}
+
+jit_type_t arithcompare_sig;
+jit_type_t native_negate_sig;
+static Lisp_Object
+native_negate (Lisp_Object v)
+{
+ if (INTEGERP (v))
+ {
+ XSETINT (v, - XINT (v));
+ return v;
+ }
+ else
+ return Fminus (1, &v);
+}
+
+jit_type_t native_point_sig;
+static Lisp_Object
+native_point (void)
+{
+ Lisp_Object v1;
+ XSETFASTINT (v1, PT);
+ return v1;
+}
+
+jit_type_t native_point_max_sig;
+static Lisp_Object
+native_point_max (void)
+{
+ Lisp_Object v1;
+ XSETFASTINT (v1, ZV);
+ return v1;
+}
+
+jit_type_t native_point_min_sig;
+static Lisp_Object
+native_point_min (void)
+{
+ Lisp_Object v1;
+ XSETFASTINT (v1, BEGV);
+ return v1;
+}
+
+jit_type_t native_current_column_sig;
+static Lisp_Object
+native_current_column (void)
+{
+ Lisp_Object v1;
+ XSETFASTINT (v1, current_column ());
+ return v1;
+}
+
+jit_type_t native_interactive_p_sig;
+static Lisp_Object
+native_interactive_p (void)
+{
+ return call0 (intern ("interactive-p"));
+}
+
+jit_type_t native_char_syntax_sig;
+static Lisp_Object
+native_char_syntax (Lisp_Object v)
+{
+ int c;
+
+ CHECK_CHARACTER (v);
+ c = XFASTINT (v);
+ if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
+ MAKE_CHAR_MULTIBYTE (c);
+ XSETFASTINT (v, syntax_code_spec[SYNTAX (c)]);
+ return v;
+}
+
+jit_type_t native_elt_sig;
+static Lisp_Object
+native_elt (Lisp_Object v1, Lisp_Object v2)
+{
+ if (CONSP (v2))
+ {
+ /* Exchange args and then do nth. */
+ EMACS_INT n;
+ CHECK_NUMBER (v2);
+ n = XINT (v2);
+ immediate_quit = 1;
+ while (--n >= 0 && CONSP (v1))
+ v1 = XCDR (v1);
+ immediate_quit = 0;
+ return CAR (v1);
+ }
+ else
+ return Felt (v1, v2);
+}
+
+jit_type_t native_car_safe_sig;
+static Lisp_Object
+native_car_safe (Lisp_Object v)
+{
+ return CAR_SAFE (v);
+}
+jit_type_t native_cdr_safe_sig;
+static Lisp_Object
+native_cdr_safe (Lisp_Object v)
+{
+ return CDR_SAFE (v);
+}
+
+jit_type_t native_number_p_sig;
+static Lisp_Object
+native_number_p (Lisp_Object v)
+{
+ return NUMBERP (v) ? Qt : Qnil;
+}
+jit_type_t native_integer_p_sig;
+static Lisp_Object
+native_integer_p (Lisp_Object v)
+{
+ return INTEGERP (v) ? Qt : Qnil;
+}
+
+jit_type_t setjmp_sig;
+
+static void
+emacs_jit_init (void)
+{
+#define JIT_SIG_(f, ret, params) \
+ do { \
+ f##_sig = \
+ jit_type_create_signature ( \
+ jit_abi_cdecl, \
+ ret, \
+ params, \
+ sizeof (params) / sizeof (params[0]), \
+ 1); \
+ } while (0)
+#define JIT_SIG(f, ret, ...) \
+ do { \
+ jit_type_t params[] = \
+ { \
+ __VA_ARGS__ \
+ }; \
+ JIT_SIG_ (f, ret, params); \
+ } while (0)
+
+ jit_context = jit_context_create();
+
+ do {
+ jit_type_t params[] =
+ {
+ jit_type_void_ptr,
+#if !defined (HAVE__SETJMP) && defined (HAVE_SIGSETJMP)
+ jit_type_sys_int
+#endif
+ };
+ setjmp_sig = jit_type_create_signature (jit_abi_cdecl,
+ jit_type_sys_int, params,
+#if !defined (HAVE__SETJMP) && defined (HAVE_SIGSETJMP)
+ 2,
+#else
+ 1,
+#endif
+ 1);
+ } while (0);
+
+ JIT_SIG (native_varref, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_ifnil, jit_type_sys_bool, jit_type_Lisp_Object);
+ JIT_SIG (native_ifnonnil, jit_type_sys_bool, jit_type_Lisp_Object);
+ JIT_SIG (native_car, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_eq, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_memq, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_cdr, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_varset, jit_type_void, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (specbind, jit_type_void, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (Ffuncall, jit_type_Lisp_Object, jit_type_nuint, jit_type_void_ptr);
+ JIT_SIG (native_unbind_to, jit_type_Lisp_Object, jit_type_nuint,
jit_type_Lisp_Object);
+ JIT_SIG (unbind_to, jit_type_Lisp_Object, jit_type_nuint,
jit_type_Lisp_Object);
+ JIT_SIG (byte_code_quit, jit_type_void);
+ JIT_SIG (native_save_excursion, jit_type_void);
+ JIT_SIG (native_save_window_excursion, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_save_restriction, jit_type_void);
+ JIT_SIG (native_catch, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_pophandler, jit_type_void);
+ JIT_SIG (native_pushhandler1, jit_type_void_ptr, jit_type_create_pointer
(jit_type_void_ptr, 1), jit_type_Lisp_Object, jit_type_nint);
+ JIT_SIG (native_pushhandler2, jit_type_void, jit_type_create_pointer
(jit_type_void_ptr, 1));
+ JIT_SIG (native_unwind_protect, jit_type_void, jit_type_Lisp_Object);
+ JIT_SIG (native_temp_output_buffer_setup, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_nth, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_symbolp, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_consp, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_stringp, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_listp, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_not, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_add1, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_sys_bool);
+ JIT_SIG (native_eqlsign, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (arithcompare, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object, jit_type_nuint);
+ JIT_SIG (native_negate, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_point, jit_type_Lisp_Object);
+ JIT_SIG (native_point_max, jit_type_Lisp_Object);
+ JIT_SIG (native_point_min, jit_type_Lisp_Object);
+ JIT_SIG (native_current_column, jit_type_Lisp_Object);
+ JIT_SIG (native_interactive_p, jit_type_Lisp_Object);
+ JIT_SIG (native_char_syntax, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_elt, jit_type_Lisp_Object, jit_type_Lisp_Object,
jit_type_Lisp_Object);
+ JIT_SIG (native_car_safe, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_cdr_safe, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_number_p, jit_type_Lisp_Object, jit_type_Lisp_Object);
+ JIT_SIG (native_integer_p, jit_type_Lisp_Object, jit_type_Lisp_Object);
+}
+
+static Lisp_Object
+jit_exec (Lisp_Object byte_code, Lisp_Object args_template, ptrdiff_t nargs,
Lisp_Object *args)
+{
+ Lisp_Object *top;
+ Lisp_Object maxdepth = XVECTOR (byte_code)->contents[COMPILED_STACK_DEPTH];
+
+ CHECK_NATNUM (maxdepth);
+ if (MAX_ALLOCA / word_size <= XFASTINT (maxdepth))
+ memory_full (SIZE_MAX);
+ top = alloca ((XFASTINT (maxdepth) + 1) * sizeof *top);
+
+ if (INTEGERP (args_template))
+ {
+ ptrdiff_t at = XINT (args_template);
+ bool rest = (at & 128) != 0;
+ int mandatory = at & 127;
+ ptrdiff_t nonrest = at >> 8;
+ eassert (mandatory <= nonrest);
+ if (nargs <= nonrest)
+ {
+ ptrdiff_t i;
+ for (i = 0 ; i < nargs; i++, args++)
+ PUSH (*args);
+ if (nargs < mandatory)
+ /* Too few arguments. */
+ Fsignal (Qwrong_number_of_arguments,
+ list2 (Fcons (make_number (mandatory),
+ rest ? Qand_rest : make_number (nonrest)),
+ make_number (nargs)));
+ else
+ {
+ for (; i < nonrest; i++)
+ PUSH (Qnil);
+ if (rest)
+ PUSH (Qnil);
+ }
+ }
+ else if (rest)
+ {
+ ptrdiff_t i;
+ for (i = 0 ; i < nonrest; i++, args++)
+ PUSH (*args);
+ PUSH (Flist (nargs - nonrest, args));
+ }
+ else
+ /* Too many arguments. */
+ Fsignal (Qwrong_number_of_arguments,
+ list2 (Fcons (make_number (mandatory), make_number (nonrest)),
+ make_number (nargs)));
+ }
+ else if (! NILP (args_template))
+ /* We should push some arguments on the stack. */
+ {
+ error ("Unknown args template!");
+ }
+
+ {
+ Lisp_Object (*func)(Lisp_Object *) =
+ (Lisp_Object (*)(Lisp_Object *))AREF (byte_code, COMPILED_JIT_ID);
+ return func (top);
+ }
+}
+
+static void
+jit_byte_code__ (Lisp_Object byte_code)
+{
+ ptrdiff_t count = SPECPDL_INDEX ();
+ int op;
+ Lisp_Object *vectorp;
+#ifdef BYTE_CODE_SAFE
+ ptrdiff_t const_length;
+ Lisp_Object *stacke;
+#endif
+ ptrdiff_t bytestr_length;
+ struct byte_stack stack;
+ Lisp_Object bytestr;
+ Lisp_Object vector;
+ Lisp_Object maxdepth;
+ Lisp_Object *top;
+ enum handlertype type;
+
+ /* jit-specific variables */
+ jit_function_t this_func;
+ jit_type_t params[1];
+ jit_type_t signature;
+ jit_label_t *labels;
+ jit_value_t stackv;
+
+ /* ensure this is a byte-coded function _before_ doing anything else */
+ CHECK_COMPILED (byte_code);
+
+ /* check if function has already been compiled */
+ if (XVECTOR (byte_code)->contents[COMPILED_JIT_ID])
+ {
+ return;
+ }
+ else if (!jit_context)
+ {
+ /* jit is not yet initialized */
+ emacs_jit_init ();
+ }
+
+ bytestr = XVECTOR (byte_code)->contents[COMPILED_BYTECODE];
+ vector = XVECTOR (byte_code)->contents[COMPILED_CONSTANTS];
+ maxdepth = XVECTOR (byte_code)->contents[COMPILED_STACK_DEPTH];
+ CHECK_STRING (bytestr);
+ CHECK_VECTOR (vector);
+ CHECK_NATNUM (maxdepth);
+
+#ifdef BYTE_CODE_SAFE
+ const_length = ASIZE (vector);
+#endif
+
+ if (STRING_MULTIBYTE (bytestr))
+ /* BYTESTR must have been produced by Emacs 20.2 or the earlier
+ because they produced a raw 8-bit string for byte-code and now
+ such a byte-code string is loaded as multibyte while raw 8-bit
+ characters converted to multibyte form. Thus, now we must
+ convert them back to the originally intended unibyte form. */
+ bytestr = Fstring_as_unibyte (bytestr);
+
+ bytestr_length = SBYTES (bytestr);
+ vectorp = XVECTOR (vector)->contents;
+
+ stack.byte_string = bytestr;
+ stack.pc = stack.byte_string_start = SDATA (bytestr);
+ if (MAX_ALLOCA / word_size <= XFASTINT (maxdepth))
+ memory_full (SIZE_MAX);
+#if BYTE_MAINTAIN_TOP
+ stack.top = NULL;
+#endif
+ stack.next = byte_stack_list;
+ byte_stack_list = &stack;
+
+ /* prepare for jit */
+ jit_context_build_start (jit_context);
+ params[0] = jit_type_void_ptr;
+ signature = jit_type_create_signature (jit_abi_cdecl, jit_type_nuint,
params, 1, 1);
+ this_func = jit_function_create (jit_context, signature);
+ stackv = jit_value_get_param (this_func, 0);
+ labels = alloca (sizeof (*labels) * SBYTES (bytestr));
+ {
+ /* give each instruction a label. the labels won't be initialized
+ until we attach code to them, but they work as a placeholder. */
+ int i;
+ for (i = 0; i < SBYTES (bytestr); i++)
+ labels[i] = jit_label_undefined;
+ }
+
+ while (stack.pc < stack.byte_string_start + bytestr_length)
+ {
+#ifndef BYTE_CODE_THREADED
+ op = FETCH;
+#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 \
+ do { \
+ if (stack.pc >= stack.byte_string_start + bytestr_length) \
+ goto exit; \
+ else \
+ { \
+ /* Create a new block and attach a label to it. */ \
+ /* Since fetching the instruction incrememnts pc, do */ \
+ /* this before we fetch the instruction, so pc is right. */ \
+ jit_insn_label (this_func, &labels[JIT_PC]); \
+ op = FETCH; \
+ goto *(targets[op]); \
+ } \
+ } while (0)
+ /* 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 (Bstack_ref): 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
+
+#if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Woverride-init"
+#elif defined __clang__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Winitializer-overrides"
+#endif
+
+ /* This is the dispatch table for the threaded interpreter. */
+ static const void *const targets[256] =
+ {
+ [0 ... (Bconstant - 1)] = &&insn_default,
+ [Bconstant ... 255] = &&insn_Bconstant,
+
+#define DEFINE(name, value) LABEL (name) ,
+ BYTE_CODES
+#undef DEFINE
+ };
+
+#if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) || defined __clang__
+# pragma GCC diagnostic pop
+#endif
+
+#endif
+
+#define JIT_PC (stack.pc - stack.byte_string_start)
+#define JIT_NEED_STACK jit_value_ref (this_func, stackv)
+#define JIT_NEXT \
+ do { \
+ if (!jit_insn_branch ( \
+ this_func, \
+ &labels[JIT_PC])) \
+ emacs_abort (); \
+ } while (0)
+
+#define JIT_INC(v, n) \
+ do { \
+ jit_value_t i = \
+ jit_insn_add_relative ( \
+ this_func, \
+ v, \
+ (jit_nint )n); \
+ if (!i) \
+ emacs_abort (); \
+ else if (!jit_insn_store ( \
+ this_func, \
+ v, \
+ i)) \
+ emacs_abort (); \
+ } while (0)
+
+#define JIT_PUSH(v) \
+ do { \
+ JIT_INC (stackv, sizeof (Lisp_Object)); \
+ if (!jit_insn_store_relative ( \
+ this_func, \
+ stackv, \
+ (jit_nint )0, \
+ v)) \
+ emacs_abort (); \
+ } while (0)
+
+#define JIT_TOP(v) \
+ do { \
+ v = jit_insn_load_relative ( \
+ this_func, \
+ stackv, \
+ (jit_nint )0, \
+ jit_type_Lisp_Object); \
+ if (!v) \
+ emacs_abort (); \
+ } while (0)
+
+#define JIT_POP(v) \
+ do { \
+ JIT_TOP (v); \
+ JIT_INC (stackv, -sizeof (Lisp_Object)); \
+ } while (0)
+
+#define JIT_CALL(f, args, n) \
+ jit_insn_call_native ( \
+ this_func, \
+ #f, \
+ (void*)&f, \
+ f##_sig, \
+ args, \
+ n, \
+ JIT_CALL_NOTHROW)
+
+#define JIT_CALL_ARGS(r, f, ...) \
+ do { \
+ jit_value_t params[] = \
+ { \
+ __VA_ARGS__ \
+ }; \
+ r = JIT_CALL ( \
+ f, \
+ params, \
+ sizeof (params) / sizeof (params[0])); \
+ } while (0)
+
+#define JIT_CONSTANT(t, v) \
+ jit_value_create_nint_constant ( \
+ this_func, \
+ t, \
+ v)
+
+#define JIT_CALL_WITH_STACK_N(f, n) \
+ do { \
+ jit_type_t params[n]; \
+ jit_value_t args[n]; \
+ jit_value_t ret; \
+ jit_type_t f##_sig; \
+ int i; \
+ for (i = 0; i < n; i++) \
+ params[i] = jit_type_Lisp_Object; \
+ JIT_SIG_ (f, jit_type_Lisp_Object, params); \
+ JIT_NEED_STACK; \
+ for (i = 1; i <= n; i++) \
+ JIT_POP (args[n-i]); \
+ ret = JIT_CALL (f, args, n); \
+ JIT_PUSH (ret); \
+ } while (0)
+
+#define JIT_CALL_WITH_STACK_MANY(f, n) \
+ do { \
+ jit_value_t ret; \
+ jit_type_t f##_sig; \
+ JIT_SIG ( \
+ f, \
+ jit_type_Lisp_Object, \
+ jit_type_nuint, \
+ jit_type_void_ptr); \
+ JIT_NEED_STACK; \
+ JIT_INC (stackv, -(n - 1) * sizeof (Lisp_Object)); \
+ JIT_CALL_ARGS ( \
+ ret, \
+ f, \
+ JIT_CONSTANT (jit_type_nuint, n), \
+ stackv); \
+ JIT_INC (stackv, -sizeof (Lisp_Object)); \
+ JIT_PUSH (ret); \
+ } while (0)
+
+#ifndef BYTE_CODE_THREADED
+ /* create a new block and attach a label to it */
+ jit_insn_label (this_func, &labels[JIT_PC]);
+#endif
+
+ FIRST
+ {
+ CASE (Bvarref7):
+ op = FETCH2;
+ goto varref;
+
+ 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 (Bvarref6):
+ op = FETCH;
+ varref:
+ {
+ jit_value_t v1, v2;
+ JIT_NEED_STACK;
+ v1 = JIT_CONSTANT (jit_type_nuint, vectorp[op]);
+ JIT_CALL_ARGS (v2, native_varref, v1);
+ JIT_PUSH (v2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcar):
+ {
+ JIT_CALL_WITH_STACK_N (native_car, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Beq):
+ {
+ JIT_CALL_WITH_STACK_N (native_eq, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmemq):
+ {
+ JIT_CALL_WITH_STACK_N (native_memq, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcdr):
+ {
+ JIT_CALL_WITH_STACK_N (native_cdr, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bvarset):
+ CASE (Bvarset1):
+ CASE (Bvarset2):
+ CASE (Bvarset3):
+ CASE (Bvarset4):
+ CASE (Bvarset5):
+ op -= Bvarset;
+ goto varset;
+
+ CASE (Bvarset7):
+ op = FETCH2;
+ goto varset;
+
+ CASE (Bvarset6):
+ op = FETCH;
+ varset:
+ {
+ jit_value_t sym, val, x;
+ JIT_NEED_STACK;
+ sym = JIT_CONSTANT (jit_type_Lisp_Object, vectorp[op]);
+ JIT_POP (val);
+ JIT_CALL_ARGS (x, native_varset, sym, val);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bdup):
+ {
+ jit_value_t x;
+ JIT_NEED_STACK;
+ JIT_TOP (x);
+ JIT_PUSH (x);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ /* ------------------ */
+
+ CASE (Bvarbind6):
+ op = FETCH;
+ goto varbind;
+
+ CASE (Bvarbind7):
+ op = FETCH2;
+ goto varbind;
+
+ CASE (Bvarbind):
+ CASE (Bvarbind1):
+ CASE (Bvarbind2):
+ CASE (Bvarbind3):
+ CASE (Bvarbind4):
+ CASE (Bvarbind5):
+ op -= Bvarbind;
+ varbind:
+ {
+ jit_value_t v1, v2, x;
+ JIT_NEED_STACK;
+ v1 = JIT_CONSTANT (jit_type_Lisp_Object, vectorp[op]);
+ JIT_POP (v2);
+ JIT_CALL_ARGS (x, specbind, v1, v2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcall6):
+ op = FETCH;
+ goto docall;
+
+ CASE (Bcall7):
+ op = FETCH2;
+ goto docall;
+
+ CASE (Bcall):
+ CASE (Bcall1):
+ CASE (Bcall2):
+ CASE (Bcall3):
+ CASE (Bcall4):
+ CASE (Bcall5):
+ op -= Bcall;
+ docall:
+ {
+ JIT_NEED_STACK;
+ JIT_CALL_WITH_STACK_MANY (Ffuncall, op + 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bunbind6):
+ op = FETCH;
+ goto dounbind;
+
+ CASE (Bunbind7):
+ op = FETCH2;
+ goto dounbind;
+
+ CASE (Bunbind):
+ CASE (Bunbind1):
+ CASE (Bunbind2):
+ CASE (Bunbind3):
+ CASE (Bunbind4):
+ CASE (Bunbind5):
+ op -= Bunbind;
+ dounbind:
+ {
+ jit_value_t args[] =
+ {
+ JIT_CONSTANT (jit_type_nuint, op),
+ JIT_CONSTANT (jit_type_Lisp_Object, Qnil)
+ };
+ JIT_CALL (native_unbind_to, args, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ 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. */
+ {
+ jit_value_t args[] =
+ {
+ JIT_CONSTANT (jit_type_nuint, count),
+ JIT_CONSTANT (jit_type_Lisp_Object, Qnil)
+ };
+ JIT_CALL (unbind_to, args, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bgoto):
+ {
+ jit_value_t v;
+ op = FETCH2;
+ CHECK_RANGE (op);
+ JIT_CALL (byte_code_quit, NULL, 0);
+ jit_insn_branch (
+ this_func,
+ &labels[op]);
+ NEXT;
+ }
+
+ CASE (Bgotoifnil):
+ CASE (BRgotoifnil):
+ CASE (Bgotoifnonnil):
+ CASE (BRgotoifnonnil):
+ CASE (Bgotoifnilelsepop):
+ CASE (BRgotoifnilelsepop):
+ CASE (Bgotoifnonnilelsepop):
+ CASE (BRgotoifnonnilelsepop):
+ {
+ jit_value_t v2, v3;
+ int insn = op;
+ if (insn >= Bgotoifnil && insn <= Bgotoifnonnilelsepop)
+ op = FETCH2;
+ else
+ {
+ op = FETCH - 128;
+ op += (stack.pc - stack.byte_string_start);
+ }
+ CHECK_RANGE (op);
+ JIT_NEED_STACK;
+ JIT_POP (v2);
+ if (insn == Bgotoifnil || insn == BRgotoifnil
+ || insn == Bgotoifnilelsepop || insn == BRgotoifnilelsepop)
+ JIT_CALL_ARGS (v3, native_ifnil, v2);
+ else
+ JIT_CALL_ARGS (v3, native_ifnonnil, v2);
+ if (insn == Bgotoifnilelsepop || insn == Bgotoifnonnilelsepop
+ || insn == BRgotoifnilelsepop || insn == BRgotoifnonnilelsepop)
+ JIT_PUSH (v2);
+ jit_insn_branch_if (
+ this_func,
+ v3,
+ &labels[op]);
+ if (insn == Bgotoifnilelsepop || insn == Bgotoifnonnilelsepop
+ || insn == BRgotoifnilelsepop || insn == BRgotoifnonnilelsepop)
+ JIT_INC (stackv, -sizeof (Lisp_Object));
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (BRgoto):
+ {
+ op = FETCH - 128;
+ const int dest = (stack.pc - stack.byte_string_start) + op;
+ JIT_CALL (byte_code_quit, NULL, 0);
+ jit_insn_branch (
+ this_func,
+ &labels[dest]);
+ NEXT;
+ }
+
+ CASE (Breturn):
+ {
+ jit_value_t v;
+ JIT_NEED_STACK;
+ JIT_POP (v);
+ jit_insn_return (this_func, v);
+ NEXT;
+ }
+
+ CASE (Bdiscard):
+ {
+ JIT_NEED_STACK;
+ JIT_INC (stackv, -sizeof (Lisp_Object));
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bconstant2):
+ {
+ jit_value_t v = JIT_CONSTANT (jit_type_Lisp_Object,
vectorp[FETCH2]);
+ JIT_NEED_STACK;
+ JIT_PUSH (v);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsave_excursion):
+ {
+ JIT_CALL (native_save_excursion, NULL, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsave_current_buffer): /* Obsolete since ??. */
+ CASE (Bsave_current_buffer_1):
+ {
+ jit_type_t record_unwind_current_buffer_sig;
+ JIT_SIG (record_unwind_current_buffer, jit_type_void);
+ JIT_CALL (record_unwind_current_buffer, NULL, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsave_window_excursion): /* Obsolete since 24.1. */
+ {
+ JIT_CALL_WITH_STACK_N (native_save_window_excursion, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsave_restriction):
+ JIT_CALL (native_save_restriction, NULL, 0);
+ JIT_NEXT;
+ NEXT;
+
+ CASE (Bcatch): /* Obsolete since 24.4. */
+ {
+ JIT_CALL_WITH_STACK_N (native_catch, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bpushcatch): /* New in 24.4. */
+ type = CATCHER;
+ goto pushhandler;
+ CASE (Bpushconditioncase): /* New in 24.4. */
+ type = CONDITION_CASE;
+ pushhandler:
+ {
+ jit_label_t new_label;
+ jit_value_t tag, stackp, jmp, result, result2, typev;
+ int dest = FETCH2;
+ JIT_NEED_STACK;
+ JIT_POP (tag);
+ stackp = jit_insn_address_of (this_func, stackv);
+ typev = JIT_CONSTANT (jit_type_nint, type);
+ JIT_CALL_ARGS (jmp, native_pushhandler1, stackp, tag, typev);
+ do {
+ void *f;
+ int n;
+ jit_value_t args[2] = { jmp };
+#ifdef HAVE__SETJMP
+ f = (void *)&_setjmp;
+ n = 1;
+#elif defined HAVE_SIGSETJMP
+ f = (void *)&sigsetjmp;
+ n = 2;
+ args[1] = JIT_CONSTANT (jit_type_sys_int, 0);
+#else
+ f = (void *)&setjmp;
+ n = 1;
+#endif
+ result = jit_insn_call_native (this_func, "setjmp", f,
+ setjmp_sig, args, n,
+ JIT_CALL_NOTHROW);
+ } while (0);
+ jit_insn_branch_if_not (this_func, result, &labels[JIT_PC]);
+ JIT_CALL (native_pushhandler2, &stackp, 1);
+ jit_insn_branch (this_func, &labels[dest]);
+ NEXT;
+ }
+
+ CASE (Bpophandler): /* New in 24.4. */
+ {
+ JIT_CALL (native_pophandler, NULL, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bunwind_protect): /* FIXME: avoid closure for lexbind. */
+ {
+ jit_value_t handler;
+ JIT_NEED_STACK;
+ JIT_POP (handler);
+ JIT_CALL (native_unwind_protect, &handler, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcondition_case): /* Obsolete since 24.4. */
+ {
+ JIT_CALL_WITH_STACK_N (internal_lisp_condition_case, 3);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Btemp_output_buffer_setup): /* Obsolete since 24.1. */
+ {
+ JIT_NEED_STACK;
+ JIT_CALL_WITH_STACK_N (native_temp_output_buffer_setup, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Btemp_output_buffer_show): /* Obsolete since 24.1. */
+ {
+ jit_type_t temp_output_buffer_show_sig;
+ jit_value_t v1, v2, c, q, x;
+ JIT_NEED_STACK;
+ JIT_SIG (temp_output_buffer_show,
+ jit_type_void,
+ jit_type_Lisp_Object);
+ JIT_POP (v1);
+ JIT_POP (v2);
+ JIT_CALL (temp_output_buffer_show, &v2, 1);
+ JIT_PUSH (v1);
+ c = JIT_CONSTANT (jit_type_nuint, 1);
+ q = JIT_CONSTANT (jit_type_Lisp_Object, Qnil);
+ JIT_CALL_ARGS (x, native_unbind_to, c, q);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnth):
+ {
+ JIT_CALL_WITH_STACK_N (native_nth, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsymbolp):
+ CASE (Bconsp):
+ CASE (Bstringp):
+ CASE (Blistp):
+ CASE (Bnot):
+ {
+ jit_value_t v1, v2;
+ JIT_NEED_STACK;
+ JIT_POP (v1);
+ switch (op)
+ {
+ case Bsymbolp:
+ JIT_CALL_ARGS (v2, native_symbolp, v1);
+ break;
+ case Bconsp:
+ JIT_CALL_ARGS (v2, native_consp, v1);
+ break;
+ case Bstringp:
+ JIT_CALL_ARGS (v2, native_stringp, v1);
+ break;
+ case Blistp:
+ JIT_CALL_ARGS (v2, native_listp, v1);
+ break;
+ case Bnot:
+ default:
+ JIT_CALL_ARGS (v2, native_not, v1);
+ break;
+ }
+ JIT_PUSH (v2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcons):
+ {
+ JIT_CALL_WITH_STACK_N (Fcons, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Blist1):
+ {
+ JIT_CALL_WITH_STACK_N (list1, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Blist2):
+ {
+ JIT_CALL_WITH_STACK_N (list2, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Blist3):
+ CASE (Blist4):
+ CASE (BlistN):
+ {
+ size_t temp;
+ if (op == BlistN)
+ {
+ temp = FETCH;
+ }
+ else
+ {
+ if (op == Blist3)
+ temp = 3;
+ else
+ temp = 4;
+ }
+ JIT_CALL_WITH_STACK_MANY (Flist, temp);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Blength):
+ {
+ JIT_CALL_WITH_STACK_N (Flength, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Baref):
+ {
+ JIT_CALL_WITH_STACK_N (Faref, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Baset):
+ {
+ JIT_CALL_WITH_STACK_N (Faset, 3);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsymbol_value):
+ {
+ JIT_CALL_WITH_STACK_N (Fsymbol_value, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+ CASE (Bsymbol_function):
+ {
+ JIT_CALL_WITH_STACK_N (Fsymbol_function, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bset):
+ {
+ JIT_CALL_WITH_STACK_N (Fset, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bfset):
+ {
+ JIT_CALL_WITH_STACK_N (Ffset, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bget):
+ {
+ JIT_CALL_WITH_STACK_N (Fget, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsubstring):
+ {
+ JIT_CALL_WITH_STACK_N (Fsubstring, 3);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bconcat2):
+ CASE (Bconcat3):
+ CASE (Bconcat4):
+ CASE (BconcatN):
+ {
+ size_t n;
+ if (op == BconcatN)
+ n = FETCH;
+ else
+ n = op - Bconcat2 + 2;
+ JIT_CALL_WITH_STACK_MANY (Fconcat, n);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsub1):
+ {
+ jit_value_t v1, v2;
+ JIT_NEED_STACK;
+ JIT_POP (v1);
+ JIT_CALL_ARGS (v2, native_add1, v1, JIT_CONSTANT
(jit_type_sys_bool, 0));
+ JIT_PUSH (v2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Badd1):
+ {
+ jit_value_t v1, v2;
+ JIT_NEED_STACK;
+ JIT_POP (v1);
+ JIT_CALL_ARGS (v2, native_add1, v1, JIT_CONSTANT
(jit_type_sys_bool, 1));
+ JIT_PUSH (v2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Beqlsign):
+ {
+ JIT_CALL_WITH_STACK_N (native_eqlsign, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bgtr):
+ CASE (Blss):
+ CASE (Bleq):
+ CASE (Bgeq):
+ {
+ jit_value_t v1, v2, v3, c;
+ enum Arith_Comparison v[] =
+ {
+ ARITH_GRTR,
+ ARITH_LESS,
+ ARITH_LESS_OR_EQUAL,
+ ARITH_GRTR_OR_EQUAL
+ };
+ JIT_NEED_STACK;
+ c = JIT_CONSTANT (jit_type_nuint, v[op-Bgtr]);
+ JIT_POP (v2);
+ JIT_POP (v1);
+ JIT_CALL_ARGS (v3, arithcompare, v1, v2, c);
+ JIT_PUSH (v3);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bdiff):
+ {
+ JIT_CALL_WITH_STACK_MANY (Fminus, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnegate):
+ {
+ JIT_CALL_WITH_STACK_N (native_negate, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bplus):
+ {
+ JIT_CALL_WITH_STACK_MANY (Fplus, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmax):
+ {
+ JIT_CALL_WITH_STACK_MANY (Fmax, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmin):
+ {
+ JIT_CALL_WITH_STACK_MANY (Fmin, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmult):
+ {
+ JIT_CALL_WITH_STACK_MANY (Ftimes, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bquo):
+ {
+ JIT_CALL_WITH_STACK_MANY (Fquo, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Brem):
+ {
+ JIT_CALL_WITH_STACK_N (Frem, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bpoint):
+ {
+ JIT_CALL_WITH_STACK_N (native_point, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bgoto_char):
+ {
+ JIT_CALL_WITH_STACK_N (Fgoto_char, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Binsert):
+ {
+ JIT_CALL_WITH_STACK_MANY (Finsert, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (BinsertN):
+ {
+ /* FETCH must not appear in the macro reference below, otherwise
+ the macro expansion will contain multiple instances OF FETCH */
+ Lisp_Object n = FETCH;
+ JIT_CALL_WITH_STACK_MANY (Finsert, n);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bpoint_max):
+ {
+ JIT_CALL_WITH_STACK_N (native_point_max, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bpoint_min):
+ {
+ JIT_CALL_WITH_STACK_N (native_point_min, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bchar_after):
+ {
+ JIT_CALL_WITH_STACK_N (Fchar_after, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bfollowing_char):
+ {
+ JIT_CALL_WITH_STACK_N (Ffollowing_char, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bpreceding_char):
+ {
+ JIT_CALL_WITH_STACK_N (Fprevious_char, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcurrent_column):
+ {
+ JIT_CALL_WITH_STACK_N (native_current_column, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bindent_to):
+ {
+ JIT_PUSH (JIT_CONSTANT (jit_type_Lisp_Object, Qnil));
+ JIT_CALL_WITH_STACK_N (Findent_to, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Beolp):
+ {
+ JIT_CALL_WITH_STACK_N (Feolp, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Beobp):
+ {
+ JIT_CALL_WITH_STACK_N (Feobp, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bbolp):
+ {
+ JIT_CALL_WITH_STACK_N (Fbolp, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bbobp):
+ {
+ JIT_CALL_WITH_STACK_N (Fbobp, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcurrent_buffer):
+ {
+ JIT_CALL_WITH_STACK_N (Fcurrent_buffer, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bset_buffer):
+ {
+ JIT_CALL_WITH_STACK_N (Fset_buffer, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Binteractive_p): /* Obsolete since 24.1. */
+ {
+ JIT_CALL_WITH_STACK_N (native_interactive_p, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bforward_char):
+ {
+ JIT_CALL_WITH_STACK_N (Fforward_char, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bforward_word):
+ {
+ JIT_CALL_WITH_STACK_N (Fforward_word, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bskip_chars_forward):
+ {
+ JIT_CALL_WITH_STACK_N (Fskip_chars_forward, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bskip_chars_backward):
+ {
+ JIT_CALL_WITH_STACK_N (Fskip_chars_backward, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bforward_line):
+ {
+ JIT_CALL_WITH_STACK_N (Fforward_line, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bchar_syntax):
+ {
+ JIT_CALL_WITH_STACK_N (native_char_syntax, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bbuffer_substring):
+ {
+ JIT_CALL_WITH_STACK_N (Fbuffer_substring, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bdelete_region):
+ {
+ JIT_CALL_WITH_STACK_N (Fdelete_region, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnarrow_to_region):
+ {
+ JIT_CALL_WITH_STACK_N (Fnarrow_to_region, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bwiden):
+ {
+ JIT_CALL_WITH_STACK_N (Fwiden, 0);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bend_of_line):
+ {
+ JIT_CALL_WITH_STACK_N (Fend_of_line, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bset_marker):
+ {
+ JIT_CALL_WITH_STACK_N (Fset_marker, 3);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmatch_beginning):
+ {
+ JIT_CALL_WITH_STACK_N (Fmatch_beginning, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmatch_end):
+ {
+ JIT_CALL_WITH_STACK_N (Fmatch_end, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bupcase):
+ {
+ JIT_CALL_WITH_STACK_N (Fupcase, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bdowncase):
+ {
+ JIT_CALL_WITH_STACK_N (Fdowncase, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bstringeqlsign):
+ {
+ JIT_CALL_WITH_STACK_N (Fstring_equal, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bstringlss):
+ {
+ JIT_CALL_WITH_STACK_N (Fstring_lessp, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bequal):
+ {
+ JIT_CALL_WITH_STACK_N (Fequal, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnthcdr):
+ {
+ JIT_CALL_WITH_STACK_N (Fnthcdr, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Belt):
+ {
+ JIT_CALL_WITH_STACK_N (native_elt, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bmember):
+ {
+ JIT_CALL_WITH_STACK_N (Fmember, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bassq):
+ {
+ JIT_CALL_WITH_STACK_N (Fassq, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnreverse):
+ {
+ JIT_CALL_WITH_STACK_N (Fnreverse, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsetcar):
+ {
+ JIT_CALL_WITH_STACK_N (Fsetcar, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bsetcdr):
+ {
+ JIT_CALL_WITH_STACK_N (Fsetcdr, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcar_safe):
+ {
+ JIT_CALL_WITH_STACK_N (native_car_safe, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bcdr_safe):
+ {
+ JIT_CALL_WITH_STACK_N (native_cdr_safe, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnconc):
+ {
+ JIT_CALL_WITH_STACK_MANY (Fnconc, 2);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bnumberp):
+ {
+ JIT_CALL_WITH_STACK_N (native_number_p, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE (Bintegerp):
+ {
+ JIT_CALL_WITH_STACK_N (native_integer_p, 1);
+ JIT_NEXT;
+ NEXT;
+ }
+
+#ifdef BYTE_CODE_SAFE
+ /* These are intentionally written using 'case' syntax,
+ because they are incompatible with the threaded
+ interpreter. */
+
+ case Bset_mark:
+ error ("set-mark is an obsolete bytecode");
+ break;
+ case Bscan_buffer:
+ error ("scan-buffer is an obsolete bytecode");
+ break;
+#endif
+
+ CASE_ABORT:
+ /* Actually this is Bstack_ref with offset 0, but we use Bdup
+ for that instead. */
+ /* CASE (Bstack_ref): */
+ call3 (Qerror,
+ build_string ("Invalid byte opcode: op=%s, ptr=%d"),
+ make_number (op),
+ make_number ((stack.pc - 1) - stack.byte_string_start));
+
+ /* Handy byte-codes for lexical binding. */
+ CASE (Bstack_ref1):
+ CASE (Bstack_ref2):
+ CASE (Bstack_ref3):
+ CASE (Bstack_ref4):
+ CASE (Bstack_ref5):
+ CASE (Bstack_ref6):
+ CASE (Bstack_ref7):
+ {
+ jit_value_t v1;
+ int offs = op - Bstack_ref;
+ if (offs == 6)
+ offs = FETCH;
+ else if (offs == 7)
+ offs = FETCH2;
+
+ JIT_NEED_STACK;
+ JIT_INC (stackv, -offs * sizeof (Lisp_Object));
+ JIT_TOP (v1);
+ JIT_INC (stackv, offs * sizeof (Lisp_Object));
+ JIT_PUSH (v1);
+ JIT_NEXT;
+ NEXT;
+ }
+ CASE (Bstack_set):
+ CASE (Bstack_set2):
+ /* stack-set-0 = discard; stack-set-1 = discard-1-preserve-tos. */
+ {
+ jit_value_t v1;
+ int offs = (op == Bstack_set) ? FETCH : FETCH2;
+ JIT_NEED_STACK;
+ JIT_TOP (v1);
+ if (offs != 0)
+ JIT_INC (stackv, -(offs + 1) * sizeof (Lisp_Object));
+ JIT_PUSH (v1);
+ JIT_INC (stackv, (offs - 1) * sizeof (Lisp_Object));
+ JIT_NEXT;
+ NEXT;
+ }
+ CASE (BdiscardN):
+ {
+ op = FETCH;
+ JIT_NEED_STACK;
+ if (op & 0x80)
+ {
+ jit_value_t v1;
+ op &= 0x7F;
+ JIT_TOP (v1);
+ JIT_INC (stackv, -(op + 1) * sizeof (Lisp_Object));
+ JIT_PUSH (v1);
+ }
+ else
+ JIT_INC (stackv, -op * sizeof (Lisp_Object));
+ JIT_NEXT;
+ NEXT;
+ }
+
+ CASE_DEFAULT
+ CASE (Bconstant):
+ {
+ jit_value_t c;
+#ifdef BYTE_CODE_SAFE
+ if (op < Bconstant)
+ {
+ emacs_abort ();
+ }
+ if ((op -= Bconstant) >= const_length)
+ {
+ emacs_abort ();
+ }
+#endif
+ c = JIT_CONSTANT (jit_type_Lisp_Object, vectorp[op - Bconstant]);
+ JIT_PUSH (c);
+ JIT_NEXT;
+ NEXT;
+ }
+ }
+ }
+
+ exit:
+ byte_stack_list = byte_stack_list->next;
+
+ {
+ int err = !jit_function_compile (this_func);
+ jit_context_build_end (jit_context);
+ if (err)
+ emacs_abort ();
+ ASET (byte_code, COMPILED_JIT_ID, (Lisp_Object )jit_function_to_closure
(this_func));
+ }
+}
+
+Lisp_Object
+jit_byte_code (Lisp_Object byte_code, Lisp_Object args_template,
+ ptrdiff_t nargs, Lisp_Object *args)
+{
+ if (AREF (byte_code, COMPILED_JIT_ID))
+ return jit_exec (byte_code, args_template, nargs, args);
+ else if (!byte_code_jit_on)
+ return exec_byte_code (AREF (byte_code, COMPILED_BYTECODE),
+ AREF (byte_code, COMPILED_CONSTANTS),
+ AREF (byte_code, COMPILED_STACK_DEPTH),
+ args_template, nargs, args);
+ else
+ {
+ jit_byte_code__ (byte_code);
+ return jit_exec (byte_code, args_template, nargs, args);
+ }
+}
+
+DEFUN ("jit-compile", Fjit_compile, Sjit_compile, 1, 1, 0,
+ doc: /* Function used internally in byte-compiled code.
+ The first argument, BYTECODE, is a compiled byte code object. */)
+ (Lisp_Object byte_code)
+{
+ jit_byte_code__ (byte_code);
+ return byte_code;
+}
+
+void
+syms_of_bytecode_jit (void)
+{
+ defsubr (&Sjit_compile);
+ DEFVAR_BOOL ("byte-code-jit-on", byte_code_jit_on,
+ doc: /* If non-nil, compile byte-code to machine code
+ before execution. */);
+ byte_code_jit_on = 0;
+}
diff --git a/src/bytecode.c b/src/bytecode.c
index 9ae2e82..b6b7484 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -35,6 +35,7 @@ by Hallvard:
#include <config.h>
+#include "bytecode.h"
#include "lisp.h"
#include "blockinput.h"
#include "character.h"
@@ -48,24 +49,6 @@ by Hallvard:
#include "xterm.h"
#endif
-/*
- * define BYTE_CODE_SAFE to enable some minor sanity checking (useful for
- * debugging the byte compiler...)
- *
- * define BYTE_CODE_METER to enable generation of a byte-op usage histogram.
- */
-/* #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 code,
- as currently implemented, is incompatible with BYTE_CODE_SAFE and
- BYTE_CODE_METER. */
-#if (defined __GNUC__ && !defined __STRICT_ANSI__ \
- && !defined BYTE_CODE_SAFE && !defined BYTE_CODE_METER)
-#define BYTE_CODE_THREADED
-#endif
-
#ifdef BYTE_CODE_METER
@@ -88,246 +71,8 @@ by Hallvard:
}
#endif /* BYTE_CODE_METER */
-
-
-/* Byte codes: */
-
-#define 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 (Bpophandler, 060) \
-DEFINE (Bpushconditioncase, 061) \
-DEFINE (Bpushcatch, 062) \
- \
-DEFINE (Bnth, 070) \
-DEFINE (Bsymbolp, 071) \
-DEFINE (Bconsp, 072) \
-DEFINE (Bstringp, 073) \
-DEFINE (Blistp, 074) \
-DEFINE (Beq, 075) \
-DEFINE (Bmemq, 076) \
-DEFINE (Bnot, 077) \
-DEFINE (Bcar, 0100) \
-DEFINE (Bcdr, 0101) \
-DEFINE (Bcons, 0102) \
-DEFINE (Blist1, 0103) \
-DEFINE (Blist2, 0104) \
-DEFINE (Blist3, 0105) \
-DEFINE (Blist4, 0106) \
-DEFINE (Blength, 0107) \
-DEFINE (Baref, 0110) \
-DEFINE (Baset, 0111) \
-DEFINE (Bsymbol_value, 0112) \
-DEFINE (Bsymbol_function, 0113)
\
-DEFINE (Bset, 0114) \
-DEFINE (Bfset, 0115) \
-DEFINE (Bget, 0116) \
-DEFINE (Bsubstring, 0117) \
-DEFINE (Bconcat2, 0120)
\
-DEFINE (Bconcat3, 0121)
\
-DEFINE (Bconcat4, 0122)
\
-DEFINE (Bsub1, 0123) \
-DEFINE (Badd1, 0124) \
-DEFINE (Beqlsign, 0125)
\
-DEFINE (Bgtr, 0126) \
-DEFINE (Blss, 0127) \
-DEFINE (Bleq, 0130) \
-DEFINE (Bgeq, 0131) \
-DEFINE (Bdiff, 0132) \
-DEFINE (Bnegate, 0133) \
-DEFINE (Bplus, 0134) \
-DEFINE (Bmax, 0135) \
-DEFINE (Bmin, 0136) \
-DEFINE (Bmult, 0137) \
- \
-DEFINE (Bpoint, 0140) \
-/* Was Bmark in v17. */ \
-DEFINE (Bsave_current_buffer, 0141) /* Obsolete. */ \
-DEFINE (Bgoto_char, 0142) \
-DEFINE (Binsert, 0143) \
-DEFINE (Bpoint_max, 0144) \
-DEFINE (Bpoint_min, 0145) \
-DEFINE (Bchar_after, 0146) \
-DEFINE (Bfollowing_char, 0147) \
-DEFINE (Bpreceding_char, 0150) \
-DEFINE (Bcurrent_column, 0151) \
-DEFINE (Bindent_to, 0152) \
-DEFINE (Beolp, 0154) \
-DEFINE (Beobp, 0155) \
-DEFINE (Bbolp, 0156) \
-DEFINE (Bbobp, 0157) \
-DEFINE (Bcurrent_buffer, 0160) \
-DEFINE (Bset_buffer, 0161) \
-DEFINE (Bsave_current_buffer_1, 0162) /* Replacing Bsave_current_buffer. */ \
-DEFINE (Binteractive_p, 0164) /* Obsolete since Emacs-24.1. */
\
- \
-DEFINE (Bforward_char, 0165) \
-DEFINE (Bforward_word, 0166) \
-DEFINE (Bskip_chars_forward, 0167) \
-DEFINE (Bskip_chars_backward, 0170) \
-DEFINE (Bforward_line, 0171) \
-DEFINE (Bchar_syntax, 0172) \
-DEFINE (Bbuffer_substring, 0173) \
-DEFINE (Bdelete_region, 0174) \
-DEFINE (Bnarrow_to_region, 0175) \
-DEFINE (Bwiden, 0176) \
-DEFINE (Bend_of_line, 0177) \
- \
-DEFINE (Bconstant2, 0201) \
-DEFINE (Bgoto, 0202) \
-DEFINE (Bgotoifnil, 0203) \
-DEFINE (Bgotoifnonnil, 0204) \
-DEFINE (Bgotoifnilelsepop, 0205) \
-DEFINE (Bgotoifnonnilelsepop, 0206) \
-DEFINE (Breturn, 0207) \
-DEFINE (Bdiscard, 0210)
\
-DEFINE (Bdup, 0211) \
- \
-DEFINE (Bsave_excursion, 0212) \
-DEFINE (Bsave_window_excursion, 0213) /* Obsolete since Emacs-24.1. */
\
-DEFINE (Bsave_restriction, 0214) \
-DEFINE (Bcatch, 0215) \
- \
-DEFINE (Bunwind_protect, 0216) \
-DEFINE (Bcondition_case, 0217) \
-DEFINE (Btemp_output_buffer_setup, 0220) /* Obsolete since Emacs-24.1. */ \
-DEFINE (Btemp_output_buffer_show, 0221) /* Obsolete since Emacs-24.1. */ \
- \
-DEFINE (Bunbind_all, 0222) /* Obsolete. Never used. */ \
- \
-DEFINE (Bset_marker, 0223) \
-DEFINE (Bmatch_beginning, 0224)
\
-DEFINE (Bmatch_end, 0225) \
-DEFINE (Bupcase, 0226) \
-DEFINE (Bdowncase, 0227) \
- \
-DEFINE (Bstringeqlsign, 0230) \
-DEFINE (Bstringlss, 0231) \
-DEFINE (Bequal, 0232) \
-DEFINE (Bnthcdr, 0233) \
-DEFINE (Belt, 0234) \
-DEFINE (Bmember, 0235) \
-DEFINE (Bassq, 0236) \
-DEFINE (Bnreverse, 0237) \
-DEFINE (Bsetcar, 0240) \
-DEFINE (Bsetcdr, 0241) \
-DEFINE (Bcar_safe, 0242) \
-DEFINE (Bcdr_safe, 0243) \
-DEFINE (Bnconc, 0244) \
-DEFINE (Bquo, 0245) \
-DEFINE (Brem, 0246) \
-DEFINE (Bnumberp, 0247)
\
-DEFINE (Bintegerp, 0250) \
- \
-DEFINE (BRgoto, 0252) \
-DEFINE (BRgotoifnil, 0253) \
-DEFINE (BRgotoifnonnil, 0254) \
-DEFINE (BRgotoifnilelsepop, 0255) \
-DEFINE (BRgotoifnonnilelsepop, 0256) \
- \
-DEFINE (BlistN, 0257) \
-DEFINE (BconcatN, 0260)
\
-DEFINE (BinsertN, 0261)
\
- \
-/* Bstack_ref is code 0. */ \
-DEFINE (Bstack_set, 0262) \
-DEFINE (Bstack_set2, 0263) \
-DEFINE (BdiscardN, 0266) \
- \
-DEFINE (Bconstant, 0300)
-
-enum byte_code_op
-{
-#define DEFINE(name, value) name = value,
- BYTE_CODES
-#undef DEFINE
-
-#ifdef BYTE_CODE_SAFE
- Bscan_buffer = 0153, /* No longer generated as of v18. */
- 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. */
-
-struct byte_stack
-{
- /* Program counter. This points into the byte_string below
- 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. */
- 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. */
+/* Declared in bytecode.h */
struct byte_stack *byte_stack_list;
@@ -384,27 +129,6 @@ relocate_byte_stack (void)
#define TOP (*top)
-/* Actions that must be performed before and after calling a function
- that might GC. */
-
-#if !BYTE_MAINTAIN_TOP
-#define BEFORE_POTENTIAL_GC() ((void)0)
-#define AFTER_POTENTIAL_GC() ((void)0)
-#else
-#define BEFORE_POTENTIAL_GC() stack.top = top
-#define AFTER_POTENTIAL_GC() stack.top = NULL
-#endif
-
-/* Garbage collect if we have consed enough since the last time.
- We do this at every branch, to avoid loops that never GC. */
-
-#define MAYBE_GC() \
- do { \
- BEFORE_POTENTIAL_GC (); \
- maybe_gc (); \
- AFTER_POTENTIAL_GC (); \
- } while (0)
-
/* Check for jumping out of range. */
#ifdef BYTE_CODE_SAFE
@@ -449,7 +173,7 @@ If the third argument is incorrect, Emacs may crash. */)
return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL);
}
-static void
+void
bcall0 (Lisp_Object f)
{
Ffuncall (1, &f);
diff --git a/src/bytecode.h b/src/bytecode.h
new file mode 100644
index 0000000..020fc2e
--- /dev/null
+++ b/src/bytecode.h
@@ -0,0 +1,283 @@
+#include "lisp.h"
+
+/*
+ * define BYTE_CODE_SAFE to enable some minor sanity checking (useful for
+ * debugging the byte compiler...)
+ *
+ * define BYTE_CODE_METER to enable generation of a byte-op usage histogram.
+ */
+/* #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 code,
+ as currently implemented, is incompatible with BYTE_CODE_SAFE and
+ BYTE_CODE_METER. */
+#if (defined __GNUC__ && !defined __STRICT_ANSI__ \
+ && !defined BYTE_CODE_SAFE && !defined BYTE_CODE_METER)
+#define BYTE_CODE_THREADED
+#endif
+
+/* Byte codes: */
+
+#define 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 (Bpophandler, 060) \
+DEFINE (Bpushconditioncase, 061) \
+DEFINE (Bpushcatch, 062) \
+ \
+DEFINE (Bnth, 070) \
+DEFINE (Bsymbolp, 071) \
+DEFINE (Bconsp, 072) \
+DEFINE (Bstringp, 073) \
+DEFINE (Blistp, 074) \
+DEFINE (Beq, 075) \
+DEFINE (Bmemq, 076) \
+DEFINE (Bnot, 077) \
+DEFINE (Bcar, 0100) \
+DEFINE (Bcdr, 0101) \
+DEFINE (Bcons, 0102) \
+DEFINE (Blist1, 0103) \
+DEFINE (Blist2, 0104) \
+DEFINE (Blist3, 0105) \
+DEFINE (Blist4, 0106) \
+DEFINE (Blength, 0107) \
+DEFINE (Baref, 0110) \
+DEFINE (Baset, 0111) \
+DEFINE (Bsymbol_value, 0112) \
+DEFINE (Bsymbol_function, 0113)
\
+DEFINE (Bset, 0114) \
+DEFINE (Bfset, 0115) \
+DEFINE (Bget, 0116) \
+DEFINE (Bsubstring, 0117) \
+DEFINE (Bconcat2, 0120)
\
+DEFINE (Bconcat3, 0121)
\
+DEFINE (Bconcat4, 0122)
\
+DEFINE (Bsub1, 0123) \
+DEFINE (Badd1, 0124) \
+DEFINE (Beqlsign, 0125)
\
+DEFINE (Bgtr, 0126) \
+DEFINE (Blss, 0127) \
+DEFINE (Bleq, 0130) \
+DEFINE (Bgeq, 0131) \
+DEFINE (Bdiff, 0132) \
+DEFINE (Bnegate, 0133) \
+DEFINE (Bplus, 0134) \
+DEFINE (Bmax, 0135) \
+DEFINE (Bmin, 0136) \
+DEFINE (Bmult, 0137) \
+ \
+DEFINE (Bpoint, 0140) \
+/* Was Bmark in v17. */ \
+DEFINE (Bsave_current_buffer, 0141) /* Obsolete. */ \
+DEFINE (Bgoto_char, 0142) \
+DEFINE (Binsert, 0143) \
+DEFINE (Bpoint_max, 0144) \
+DEFINE (Bpoint_min, 0145) \
+DEFINE (Bchar_after, 0146) \
+DEFINE (Bfollowing_char, 0147) \
+DEFINE (Bpreceding_char, 0150) \
+DEFINE (Bcurrent_column, 0151) \
+DEFINE (Bindent_to, 0152) \
+DEFINE (Beolp, 0154) \
+DEFINE (Beobp, 0155) \
+DEFINE (Bbolp, 0156) \
+DEFINE (Bbobp, 0157) \
+DEFINE (Bcurrent_buffer, 0160) \
+DEFINE (Bset_buffer, 0161) \
+DEFINE (Bsave_current_buffer_1, 0162) /* Replacing Bsave_current_buffer. */ \
+DEFINE (Binteractive_p, 0164) /* Obsolete since Emacs-24.1. */
\
+ \
+DEFINE (Bforward_char, 0165) \
+DEFINE (Bforward_word, 0166) \
+DEFINE (Bskip_chars_forward, 0167) \
+DEFINE (Bskip_chars_backward, 0170) \
+DEFINE (Bforward_line, 0171) \
+DEFINE (Bchar_syntax, 0172) \
+DEFINE (Bbuffer_substring, 0173) \
+DEFINE (Bdelete_region, 0174) \
+DEFINE (Bnarrow_to_region, 0175) \
+DEFINE (Bwiden, 0176) \
+DEFINE (Bend_of_line, 0177) \
+ \
+DEFINE (Bconstant2, 0201) \
+DEFINE (Bgoto, 0202) \
+DEFINE (Bgotoifnil, 0203) \
+DEFINE (Bgotoifnonnil, 0204) \
+DEFINE (Bgotoifnilelsepop, 0205) \
+DEFINE (Bgotoifnonnilelsepop, 0206) \
+DEFINE (Breturn, 0207) \
+DEFINE (Bdiscard, 0210)
\
+DEFINE (Bdup, 0211) \
+ \
+DEFINE (Bsave_excursion, 0212) \
+DEFINE (Bsave_window_excursion, 0213) /* Obsolete since Emacs-24.1. */
\
+DEFINE (Bsave_restriction, 0214) \
+DEFINE (Bcatch, 0215) \
+ \
+DEFINE (Bunwind_protect, 0216) \
+DEFINE (Bcondition_case, 0217) \
+DEFINE (Btemp_output_buffer_setup, 0220) /* Obsolete since Emacs-24.1. */ \
+DEFINE (Btemp_output_buffer_show, 0221) /* Obsolete since Emacs-24.1. */ \
+ \
+DEFINE (Bunbind_all, 0222) /* Obsolete. Never used. */ \
+ \
+DEFINE (Bset_marker, 0223) \
+DEFINE (Bmatch_beginning, 0224)
\
+DEFINE (Bmatch_end, 0225) \
+DEFINE (Bupcase, 0226) \
+DEFINE (Bdowncase, 0227) \
+ \
+DEFINE (Bstringeqlsign, 0230) \
+DEFINE (Bstringlss, 0231) \
+DEFINE (Bequal, 0232) \
+DEFINE (Bnthcdr, 0233) \
+DEFINE (Belt, 0234) \
+DEFINE (Bmember, 0235) \
+DEFINE (Bassq, 0236) \
+DEFINE (Bnreverse, 0237) \
+DEFINE (Bsetcar, 0240) \
+DEFINE (Bsetcdr, 0241) \
+DEFINE (Bcar_safe, 0242) \
+DEFINE (Bcdr_safe, 0243) \
+DEFINE (Bnconc, 0244) \
+DEFINE (Bquo, 0245) \
+DEFINE (Brem, 0246) \
+DEFINE (Bnumberp, 0247)
\
+DEFINE (Bintegerp, 0250) \
+ \
+DEFINE (BRgoto, 0252) \
+DEFINE (BRgotoifnil, 0253) \
+DEFINE (BRgotoifnonnil, 0254) \
+DEFINE (BRgotoifnilelsepop, 0255) \
+DEFINE (BRgotoifnonnilelsepop, 0256) \
+ \
+DEFINE (BlistN, 0257) \
+DEFINE (BconcatN, 0260)
\
+DEFINE (BinsertN, 0261)
\
+ \
+/* Bstack_ref is code 0. */ \
+DEFINE (Bstack_set, 0262) \
+DEFINE (Bstack_set2, 0263) \
+DEFINE (BdiscardN, 0266) \
+ \
+DEFINE (Bconstant, 0300)
+
+enum byte_code_op
+{
+#define DEFINE(name, value) name = value,
+ BYTE_CODES
+#undef DEFINE
+
+#ifdef BYTE_CODE_SAFE
+ Bscan_buffer = 0153, /* No longer generated as of v18. */
+ 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. */
+
+struct byte_stack
+{
+ /* Program counter. This points into the byte_string below
+ 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. */
+ 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. */
+
+extern struct byte_stack *byte_stack_list;
+
+/* Actions that must be performed before and after calling a function
+ that might GC. */
+
+#if !BYTE_MAINTAIN_TOP
+#define BEFORE_POTENTIAL_GC() ((void)0)
+#define AFTER_POTENTIAL_GC() ((void)0)
+#else
+#define BEFORE_POTENTIAL_GC() stack.top = top
+#define AFTER_POTENTIAL_GC() stack.top = NULL
+#endif
+
+/* Garbage collect if we have consed enough since the last time.
+ We do this at every branch, to avoid loops that never GC. */
+
+#define MAYBE_GC() \
+ do { \
+ BEFORE_POTENTIAL_GC (); \
+ maybe_gc (); \
+ AFTER_POTENTIAL_GC (); \
+ } while (0)
+
+extern void
+bcall0 (Lisp_Object f);
diff --git a/src/data.c b/src/data.c
index 3a51129..e00e019 100644
--- a/src/data.c
+++ b/src/data.c
@@ -3495,6 +3495,7 @@ syms_of_data (void)
DEFSYM (Qsequencep, "sequencep");
DEFSYM (Qbufferp, "bufferp");
DEFSYM (Qvectorp, "vectorp");
+ DEFSYM (Qcompiledp, "compiledp");
DEFSYM (Qbool_vector_p, "bool-vector-p");
DEFSYM (Qchar_or_string_p, "char-or-string-p");
DEFSYM (Qmarkerp, "markerp");
diff --git a/src/emacs.c b/src/emacs.c
index 2480dfc..a8be985 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1396,6 +1396,7 @@ Using an Emacs configured with --with-x-toolkit=lucid
does not have this problem
syms_of_buffer ();
syms_of_bytecode ();
+ syms_of_bytecode_jit ();
syms_of_callint ();
syms_of_casefiddle ();
syms_of_casetab ();
diff --git a/src/eval.c b/src/eval.c
index fe6460d..44557b2 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2852,11 +2852,8 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
and constants vector yet, fetch them from the file. */
if (CONSP (AREF (fun, COMPILED_BYTECODE)))
Ffetch_bytecode (fun);
- return exec_byte_code (AREF (fun, COMPILED_BYTECODE),
- AREF (fun, COMPILED_CONSTANTS),
- AREF (fun, COMPILED_STACK_DEPTH),
- syms_left,
- nargs, arg_vector);
+ return jit_byte_code (fun, syms_left,
+ nargs, arg_vector);
}
lexenv = Qnil;
}
@@ -2918,10 +2915,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
and constants vector yet, fetch them from the file. */
if (CONSP (AREF (fun, COMPILED_BYTECODE)))
Ffetch_bytecode (fun);
- val = exec_byte_code (AREF (fun, COMPILED_BYTECODE),
- AREF (fun, COMPILED_CONSTANTS),
- AREF (fun, COMPILED_STACK_DEPTH),
- Qnil, 0, 0);
+ val = jit_byte_code (fun, Qnil, 0, 0);
}
return unbind_to (count, val);
diff --git a/src/lisp.h b/src/lisp.h
index b61855a..9a8ff63 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2811,6 +2811,11 @@ CHECK_VECTOR (Lisp_Object x)
CHECK_TYPE (VECTORP (x), Qvectorp, x);
}
INLINE void
+CHECK_COMPILED (Lisp_Object x)
+{
+ CHECK_TYPE (COMPILEDP (x), Qcompiledp, x);
+}
+INLINE void
CHECK_BOOL_VECTOR (Lisp_Object x)
{
CHECK_TYPE (BOOL_VECTOR_P (x), Qbool_vector_p, x);
@@ -3173,6 +3178,7 @@ struct handler
enum handlertype type;
Lisp_Object tag_or_ch;
Lisp_Object val;
+ Lisp_Object *stack;
struct handler *next;
struct handler *nextfree;
@@ -4207,6 +4213,10 @@ extern void relocate_byte_stack (void);
extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, ptrdiff_t, Lisp_Object *);
+/* Defined in bytecode-jit.c */
+extern void syms_of_bytecode_jit (void);
+extern Lisp_Object jit_byte_code (Lisp_Object, Lisp_Object, ptrdiff_t,
Lisp_Object *);
+
/* Defined in macros.c. */
extern void init_macros (void);
extern void syms_of_macros (void);