aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2020-05-19 23:22:40 -0700
committerPaul Eggert2020-05-19 23:25:16 -0700
commitf0b0105d913a94c66f230874c9269b19dbbc83bd (patch)
tree21180d9cd9266d18187e8dd4de487eed950efa14 /src
parent5352bda4eeb7415ad2bda5d74e007b4f36021e68 (diff)
downloademacs-f0b0105d913a94c66f230874c9269b19dbbc83bd.tar.gz
emacs-f0b0105d913a94c66f230874c9269b19dbbc83bd.zip
Hoist some byte-code checking out of eval
Check Lisp_Compiled objects better as they’re created, so that the byte-code interpreter needn’t do the checks each time it executes them. This improved performance of ‘make compile-always’ by 1.5% on my platform. Also, improve the quality of the (still-incomplete) checks, as this is more practical now that they’re done less often. * src/alloc.c (make_byte_code): Remove. All uses removed. (Fmake_byte_code): Put a better (though still incomplete) check here instead. Simplify by using Fvector instead of make_uninit_vector followed by memcpy, and by using XSETPVECTYPE instead of make_byte_code followed by XSETCOMPILED. * src/bytecode.c (Fbyte_code): Do sanity check and conditional translation to unibyte here instead of each time the function is executed. (exec_byte_code): Omit no-longer-necessary sanity and unibyte checking. Use SCHARS instead of SBYTES where either will do, as SCHARS is faster. * src/eval.c (fetch_and_exec_byte_code): New function. (funcall_lambda): Use it. (funcall_lambda, lambda_arity, Ffetch_bytecode): Omit no-longer-necessary sanity checks. (Ffetch_bytecode): Add sanity check if actually fetching. * src/lisp.h (XSETCOMPILED): Remove. All uses removed. * src/lread.c (read1): Check byte-code objects more thoroughly, albeit still incompletely, and do translation to unibyte here instead of each time the function is executed. (read1): Use XSETPVECYPE instead of make_byte_code. (read_vector): Omit no-longer-necessary sanity check.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c33
-rw-r--r--src/bytecode.c28
-rw-r--r--src/eval.c48
-rw-r--r--src/lisp.h2
-rw-r--r--src/lread.c26
5 files changed, 65 insertions, 72 deletions
diff --git a/src/alloc.c b/src/alloc.c
index ebc55857ea0..b7ebaa63a5b 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3421,23 +3421,6 @@ usage: (vector &rest OBJECTS) */)
3421 return val; 3421 return val;
3422} 3422}
3423 3423
3424void
3425make_byte_code (struct Lisp_Vector *v)
3426{
3427 /* Don't allow the global zero_vector to become a byte code object. */
3428 eassert (0 < v->header.size);
3429
3430 if (v->header.size > 1 && STRINGP (v->contents[1])
3431 && STRING_MULTIBYTE (v->contents[1]))
3432 /* BYTECODE-STRING must have been produced by Emacs 20.2 or the
3433 earlier because they produced a raw 8-bit string for byte-code
3434 and now such a byte-code string is loaded as multibyte while
3435 raw 8-bit characters converted to multibyte form. Thus, now we
3436 must convert them back to the original unibyte form. */
3437 v->contents[1] = Fstring_as_unibyte (v->contents[1]);
3438 XSETPVECTYPE (v, PVEC_COMPILED);
3439}
3440
3441DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0, 3424DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0,
3442 doc: /* Create a byte-code object with specified arguments as elements. 3425 doc: /* Create a byte-code object with specified arguments as elements.
3443The arguments should be the ARGLIST, bytecode-string BYTE-CODE, constant 3426The arguments should be the ARGLIST, bytecode-string BYTE-CODE, constant
@@ -3456,8 +3439,14 @@ stack before executing the byte-code.
3456usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS) */) 3439usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS) */)
3457 (ptrdiff_t nargs, Lisp_Object *args) 3440 (ptrdiff_t nargs, Lisp_Object *args)
3458{ 3441{
3459 Lisp_Object val = make_uninit_vector (nargs); 3442 if (! ((FIXNUMP (args[COMPILED_ARGLIST])
3460 struct Lisp_Vector *p = XVECTOR (val); 3443 || CONSP (args[COMPILED_ARGLIST])
3444 || NILP (args[COMPILED_ARGLIST]))
3445 && STRINGP (args[COMPILED_BYTECODE])
3446 && !STRING_MULTIBYTE (args[COMPILED_BYTECODE])
3447 && VECTORP (args[COMPILED_CONSTANTS])
3448 && FIXNATP (args[COMPILED_STACK_DEPTH])))
3449 error ("Invalid byte-code object");
3461 3450
3462 /* We used to purecopy everything here, if purify-flag was set. This worked 3451 /* We used to purecopy everything here, if purify-flag was set. This worked
3463 OK for Emacs-23, but with Emacs-24's lexical binding code, it can be 3452 OK for Emacs-23, but with Emacs-24's lexical binding code, it can be
@@ -3466,10 +3455,8 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT
3466 copied into pure space, including its free variables, which is sometimes 3455 copied into pure space, including its free variables, which is sometimes
3467 just wasteful and other times plainly wrong (e.g. those free vars may want 3456 just wasteful and other times plainly wrong (e.g. those free vars may want
3468 to be setcar'd). */ 3457 to be setcar'd). */
3469 3458 Lisp_Object val = Fvector (nargs, args);
3470 memcpy (p->contents, args, nargs * sizeof *args); 3459 XSETPVECTYPE (XVECTOR (val), PVEC_COMPILED);
3471 make_byte_code (p);
3472 XSETCOMPILED (val, p);
3473 return val; 3460 return val;
3474} 3461}
3475 3462
diff --git a/src/bytecode.c b/src/bytecode.c
index 3c90544f3f2..5ac30aa1010 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -319,6 +319,19 @@ the third, MAXDEPTH, the maximum stack depth used in this function.
319If the third argument is incorrect, Emacs may crash. */) 319If the third argument is incorrect, Emacs may crash. */)
320 (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth) 320 (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth)
321{ 321{
322 if (! (STRINGP (bytestr) && VECTORP (vector) && FIXNATP (maxdepth)))
323 error ("Invalid byte-code");
324
325 if (STRING_MULTIBYTE (bytestr))
326 {
327 /* BYTESTR must have been produced by Emacs 20.2 or earlier
328 because it produced a raw 8-bit string for byte-code and now
329 such a byte-code string is loaded as multibyte with raw 8-bit
330 characters converted to multibyte form. Convert them back to
331 the original unibyte form. */
332 bytestr = Fstring_as_unibyte (bytestr);
333 }
334
322 return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL); 335 return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL);
323} 336}
324 337
@@ -344,21 +357,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
344 int volatile this_op = 0; 357 int volatile this_op = 0;
345#endif 358#endif
346 359
347 CHECK_STRING (bytestr); 360 eassert (!STRING_MULTIBYTE (bytestr));
348 CHECK_VECTOR (vector);
349 CHECK_FIXNAT (maxdepth);
350 361
351 ptrdiff_t const_length = ASIZE (vector); 362 ptrdiff_t const_length = ASIZE (vector);
352 363 ptrdiff_t bytestr_length = SCHARS (bytestr);
353 if (STRING_MULTIBYTE (bytestr))
354 /* BYTESTR must have been produced by Emacs 20.2 or the earlier
355 because they produced a raw 8-bit string for byte-code and now
356 such a byte-code string is loaded as multibyte while raw 8-bit
357 characters converted to multibyte form. Thus, now we must
358 convert them back to the originally intended unibyte form. */
359 bytestr = Fstring_as_unibyte (bytestr);
360
361 ptrdiff_t bytestr_length = SBYTES (bytestr);
362 Lisp_Object *vectorp = XVECTOR (vector)->contents; 364 Lisp_Object *vectorp = XVECTOR (vector)->contents;
363 365
364 unsigned char quitcounter = 1; 366 unsigned char quitcounter = 1;
diff --git a/src/eval.c b/src/eval.c
index 014905ce6df..be2af2d041b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2904,6 +2904,21 @@ funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args)
2904 } 2904 }
2905} 2905}
2906 2906
2907/* Call the compiled Lisp function FUN. If we have not yet read FUN's
2908 bytecode string and constants vector, fetch them from the file first. */
2909
2910static Lisp_Object
2911fetch_and_exec_byte_code (Lisp_Object fun, Lisp_Object syms_left,
2912 ptrdiff_t nargs, Lisp_Object *args)
2913{
2914 if (CONSP (AREF (fun, COMPILED_BYTECODE)))
2915 Ffetch_bytecode (fun);
2916 return exec_byte_code (AREF (fun, COMPILED_BYTECODE),
2917 AREF (fun, COMPILED_CONSTANTS),
2918 AREF (fun, COMPILED_STACK_DEPTH),
2919 syms_left, nargs, args);
2920}
2921
2907static Lisp_Object 2922static Lisp_Object
2908apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count) 2923apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count)
2909{ 2924{
@@ -2968,9 +2983,6 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
2968 } 2983 }
2969 else if (COMPILEDP (fun)) 2984 else if (COMPILEDP (fun))
2970 { 2985 {
2971 ptrdiff_t size = PVSIZE (fun);
2972 if (size <= COMPILED_STACK_DEPTH)
2973 xsignal1 (Qinvalid_function, fun);
2974 syms_left = AREF (fun, COMPILED_ARGLIST); 2986 syms_left = AREF (fun, COMPILED_ARGLIST);
2975 if (FIXNUMP (syms_left)) 2987 if (FIXNUMP (syms_left))
2976 /* A byte-code object with an integer args template means we 2988 /* A byte-code object with an integer args template means we
@@ -2982,15 +2994,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
2982 argument-binding code below instead (as do all interpreted 2994 argument-binding code below instead (as do all interpreted
2983 functions, even lexically bound ones). */ 2995 functions, even lexically bound ones). */
2984 { 2996 {
2985 /* If we have not actually read the bytecode string 2997 return fetch_and_exec_byte_code (fun, syms_left, nargs, arg_vector);
2986 and constants vector yet, fetch them from the file. */
2987 if (CONSP (AREF (fun, COMPILED_BYTECODE)))
2988 Ffetch_bytecode (fun);
2989 return exec_byte_code (AREF (fun, COMPILED_BYTECODE),
2990 AREF (fun, COMPILED_CONSTANTS),
2991 AREF (fun, COMPILED_STACK_DEPTH),
2992 syms_left,
2993 nargs, arg_vector);
2994 } 2998 }
2995 lexenv = Qnil; 2999 lexenv = Qnil;
2996 } 3000 }
@@ -3059,16 +3063,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3059 if (CONSP (fun)) 3063 if (CONSP (fun))
3060 val = Fprogn (XCDR (XCDR (fun))); 3064 val = Fprogn (XCDR (XCDR (fun)));
3061 else 3065 else
3062 { 3066 val = fetch_and_exec_byte_code (fun, Qnil, 0, NULL);
3063 /* If we have not actually read the bytecode string
3064 and constants vector yet, fetch them from the file. */
3065 if (CONSP (AREF (fun, COMPILED_BYTECODE)))
3066 Ffetch_bytecode (fun);
3067 val = exec_byte_code (AREF (fun, COMPILED_BYTECODE),
3068 AREF (fun, COMPILED_CONSTANTS),
3069 AREF (fun, COMPILED_STACK_DEPTH),
3070 Qnil, 0, 0);
3071 }
3072 3067
3073 return unbind_to (count, val); 3068 return unbind_to (count, val);
3074} 3069}
@@ -3153,9 +3148,6 @@ lambda_arity (Lisp_Object fun)
3153 } 3148 }
3154 else if (COMPILEDP (fun)) 3149 else if (COMPILEDP (fun))
3155 { 3150 {
3156 ptrdiff_t size = PVSIZE (fun);
3157 if (size <= COMPILED_STACK_DEPTH)
3158 xsignal1 (Qinvalid_function, fun);
3159 syms_left = AREF (fun, COMPILED_ARGLIST); 3151 syms_left = AREF (fun, COMPILED_ARGLIST);
3160 if (FIXNUMP (syms_left)) 3152 if (FIXNUMP (syms_left))
3161 return get_byte_code_arity (syms_left); 3153 return get_byte_code_arity (syms_left);
@@ -3198,13 +3190,11 @@ DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
3198 3190
3199 if (COMPILEDP (object)) 3191 if (COMPILEDP (object))
3200 { 3192 {
3201 ptrdiff_t size = PVSIZE (object);
3202 if (size <= COMPILED_STACK_DEPTH)
3203 xsignal1 (Qinvalid_function, object);
3204 if (CONSP (AREF (object, COMPILED_BYTECODE))) 3193 if (CONSP (AREF (object, COMPILED_BYTECODE)))
3205 { 3194 {
3206 tem = read_doc_string (AREF (object, COMPILED_BYTECODE)); 3195 tem = read_doc_string (AREF (object, COMPILED_BYTECODE));
3207 if (!CONSP (tem)) 3196 if (! (CONSP (tem) && STRINGP (XCAR (tem))
3197 && VECTORP (XCDR (tem))))
3208 { 3198 {
3209 tem = AREF (object, COMPILED_BYTECODE); 3199 tem = AREF (object, COMPILED_BYTECODE);
3210 if (CONSP (tem) && STRINGP (XCAR (tem))) 3200 if (CONSP (tem) && STRINGP (XCAR (tem)))
diff --git a/src/lisp.h b/src/lisp.h
index ad7d67ae695..85bdc172b20 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1341,7 +1341,6 @@ dead_object (void)
1341#define XSETWINDOW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_WINDOW)) 1341#define XSETWINDOW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_WINDOW))
1342#define XSETTERMINAL(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_TERMINAL)) 1342#define XSETTERMINAL(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_TERMINAL))
1343#define XSETSUBR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUBR)) 1343#define XSETSUBR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUBR))
1344#define XSETCOMPILED(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_COMPILED))
1345#define XSETBUFFER(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BUFFER)) 1344#define XSETBUFFER(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BUFFER))
1346#define XSETCHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CHAR_TABLE)) 1345#define XSETCHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CHAR_TABLE))
1347#define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR)) 1346#define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR))
@@ -3934,7 +3933,6 @@ build_string (const char *str)
3934 3933
3935extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object); 3934extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
3936extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object); 3935extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
3937extern void make_byte_code (struct Lisp_Vector *);
3938extern struct Lisp_Vector *allocate_vector (ptrdiff_t); 3936extern struct Lisp_Vector *allocate_vector (ptrdiff_t);
3939extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t); 3937extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
3940 3938
diff --git a/src/lread.c b/src/lread.c
index 59bf529f45c..53b4e1be2df 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2966,8 +2966,26 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2966 struct Lisp_Vector *vec; 2966 struct Lisp_Vector *vec;
2967 tmp = read_vector (readcharfun, 1); 2967 tmp = read_vector (readcharfun, 1);
2968 vec = XVECTOR (tmp); 2968 vec = XVECTOR (tmp);
2969 if (vec->header.size == 0) 2969 if (! (COMPILED_STACK_DEPTH < vec->header.size
2970 invalid_syntax ("Empty byte-code object"); 2970 && (FIXNUMP (vec->contents[COMPILED_ARGLIST])
2971 || CONSP (vec->contents[COMPILED_ARGLIST])
2972 || NILP (vec->contents[COMPILED_ARGLIST]))
2973 && ((STRINGP (vec->contents[COMPILED_BYTECODE])
2974 && VECTORP (vec->contents[COMPILED_CONSTANTS]))
2975 || CONSP (vec->contents[COMPILED_BYTECODE]))
2976 && FIXNATP (vec->contents[COMPILED_STACK_DEPTH])))
2977 invalid_syntax ("Invalid byte-code object");
2978
2979 if (STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
2980 {
2981 /* BYTESTR must have been produced by Emacs 20.2 or earlier
2982 because it produced a raw 8-bit string for byte-code and
2983 now such a byte-code string is loaded as multibyte with
2984 raw 8-bit characters converted to multibyte form.
2985 Convert them back to the original unibyte form. */
2986 ASET (tmp, COMPILED_BYTECODE,
2987 Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE)));
2988 }
2971 2989
2972 if (COMPILED_DOC_STRING < vec->header.size 2990 if (COMPILED_DOC_STRING < vec->header.size
2973 && EQ (AREF (tmp, COMPILED_DOC_STRING), make_fixnum (0))) 2991 && EQ (AREF (tmp, COMPILED_DOC_STRING), make_fixnum (0)))
@@ -2986,7 +3004,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2986 ASET (tmp, COMPILED_DOC_STRING, make_ufixnum (hash)); 3004 ASET (tmp, COMPILED_DOC_STRING, make_ufixnum (hash));
2987 } 3005 }
2988 3006
2989 make_byte_code (vec); 3007 XSETPVECTYPE (vec, PVEC_COMPILED);
2990 return tmp; 3008 return tmp;
2991 } 3009 }
2992 if (c == '(') 3010 if (c == '(')
@@ -3824,8 +3842,6 @@ read_vector (Lisp_Object readcharfun, bool bytecodeflag)
3824{ 3842{
3825 Lisp_Object tem = read_list (1, readcharfun); 3843 Lisp_Object tem = read_list (1, readcharfun);
3826 ptrdiff_t size = list_length (tem); 3844 ptrdiff_t size = list_length (tem);
3827 if (bytecodeflag && size <= COMPILED_STACK_DEPTH)
3828 error ("Invalid byte code");
3829 Lisp_Object vector = make_nil_vector (size); 3845 Lisp_Object vector = make_nil_vector (size);
3830 3846
3831 Lisp_Object *ptr = XVECTOR (vector)->contents; 3847 Lisp_Object *ptr = XVECTOR (vector)->contents;