aboutsummaryrefslogtreecommitdiffstats
path: root/src/bytecode.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd2022-03-13 17:26:05 +0100
committerMattias EngdegÄrd2022-03-13 17:51:49 +0100
commit3ed79cdbf21039fa209c421f746c0b49ec33f4da (patch)
treef6d3c5dbf4f1d5ea1a413c80293b1abc52571ff3 /src/bytecode.c
parent267f41c7ce1e02f392b57aa338d387e7627df184 (diff)
downloademacs-3ed79cdbf21039fa209c421f746c0b49ec33f4da.tar.gz
emacs-3ed79cdbf21039fa209c421f746c0b49ec33f4da.zip
Separate bytecode stack
Use a dedicated stack for bytecode, instead of using the C stack. Stack frames are managed explicitly and we stay in the same exec_byte_code activation throughout bytecode function calls and returns. In other words, exec_byte_code no longer uses recursion for calling bytecode functions. This results in better performance, and bytecode recursion is no longer limited by the size of the C stack. The bytecode stack is currently of fixed size but overflow is handled gracefully by signalling a Lisp error instead of the hard crash that we get now. In addition, GC marking of the stack is now faster and more precise. Full precision could be attained if desired. * src/alloc.c (ATTRIBUTE_NO_SANITIZE_ADDRESS): Make non-static. * src/bytecode.c (enum stack_frame_index, BC_STACK_SIZE) (sf_get_ptr, sf_set_ptr, sf_get_lisp_ptr, sf_set_lisp_ptr) (sf_get_saved_pc, sf_set_saved_pc, init_bc_thread, free_bc_thread) (mark_bytecode, Finternal_stack_stats, valid_sp): New. (exec_byte_code): Adapt to use the new bytecode stack. (syms_of_bytecode): Add defsubr. * src/eval.c (unwind_to_catch): Restore saved stack frame. (push_handler_nosignal): Save stack frame. * src/lisp.h (struct handler): Add act_rec member. (get_act_rec, set_act_rec): New. * src/thread.c (mark_one_thread): Call mark_bytecode. (finalize_one_thread): Free bytecode thread state. (Fmake_thread, init_threads): Set up bytecode thread state. * src/thread.h (struct bc_thread_state): New. (struct thread_state): Add bytecode thread state.
Diffstat (limited to 'src/bytecode.c')
-rw-r--r--src/bytecode.c318
1 files changed, 268 insertions, 50 deletions
diff --git a/src/bytecode.c b/src/bytecode.c
index 7c390c0d40e..9356ebeb6cb 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -334,6 +334,166 @@ bcall0 (Lisp_Object f)
334 Ffuncall (1, &f); 334 Ffuncall (1, &f);
335} 335}
336 336
337/* Layout of the stack frame header. */
338enum stack_frame_index {
339 SFI_SAVED_FP, /* previous frame pointer */
340
341 /* In a frame called directly from C, the following two members are NULL. */
342 SFI_SAVED_TOP, /* previous stack pointer */
343 SFI_SAVED_PC, /* previous program counter */
344
345 SFI_FUN, /* current function object */
346
347 SF_SIZE /* number of words in the header */
348};
349
350/* The bytecode stack size in Lisp words.
351 This is a fairly generous amount, but:
352 - if users need more, we could allocate more, or just reserve the address
353 space and allocate on demand
354 - if threads are used more, then it might be a good idea to reduce the
355 per-thread overhead in time and space
356 - for maximum flexibility but a small runtime penalty, we could allocate
357 the stack in smaller chunks as needed
358*/
359#define BC_STACK_SIZE (512 * 1024)
360
361/* Bytecode interpreter stack:
362
363 |--------------| --
364 |fun | | ^ stack growth
365 |saved_pc | | | direction
366 |saved_top ------- |
367 fp--->|saved_fp ---- | | current frame
368 |--------------| | | | (called from bytecode in this example)
369 | (free) | | | |
370 top-->| ...stack... | | | |
371 : ... : | | |
372 |incoming args | | | |
373 |--------------| | | --
374 |fun | | | |
375 |saved_pc | | | |
376 |saved_top | | | |
377 |saved_fp |<- | | previous frame
378 |--------------| | |
379 | (free) | | |
380 | ...stack... |<---- |
381 : ... : |
382 |incoming args | |
383 |--------------| --
384 : :
385*/
386
387INLINE void *
388sf_get_ptr (Lisp_Object *fp, enum stack_frame_index index)
389{
390 return XLP (fp[index]);
391}
392
393INLINE void
394sf_set_ptr (Lisp_Object *fp, enum stack_frame_index index, void *value)
395{
396 fp[index] = XIL ((EMACS_INT)value);
397}
398
399INLINE Lisp_Object *
400sf_get_lisp_ptr (Lisp_Object *fp, enum stack_frame_index index)
401{
402 return sf_get_ptr (fp, index);
403}
404
405INLINE void
406sf_set_lisp_ptr (Lisp_Object *fp, enum stack_frame_index index,
407 Lisp_Object *value)
408{
409 sf_set_ptr (fp, index, value);
410}
411
412INLINE const unsigned char *
413sf_get_saved_pc (Lisp_Object *fp)
414{
415 return sf_get_ptr (fp, SFI_SAVED_PC);
416}
417
418INLINE void
419sf_set_saved_pc (Lisp_Object *fp, const unsigned char *value)
420{
421 sf_set_ptr (fp, SFI_SAVED_PC, (unsigned char *)value);
422}
423
424void
425init_bc_thread (struct bc_thread_state *bc)
426{
427 bc->stack = xmalloc (BC_STACK_SIZE * sizeof *bc->stack);
428 bc->stack_end = bc->stack + BC_STACK_SIZE;
429 /* Put a dummy header at the bottom to indicate the first free location. */
430 bc->fp = bc->stack;
431 memset (bc->fp, 0, SF_SIZE * sizeof *bc->stack);
432}
433
434void
435free_bc_thread (struct bc_thread_state *bc)
436{
437 xfree (bc->stack);
438}
439
440void
441mark_bytecode (struct bc_thread_state *bc)
442{
443 Lisp_Object *fp = bc->fp;
444 Lisp_Object *top = NULL; /* stack pointer of topmost frame not known */
445 for (;;)
446 {
447 Lisp_Object *next_fp = sf_get_lisp_ptr (fp, SFI_SAVED_FP);
448 /* Only the dummy frame at the bottom has saved_fp = NULL. */
449 if (!next_fp)
450 break;
451 mark_object (fp[SFI_FUN]);
452 Lisp_Object *frame_base = next_fp + SF_SIZE;
453 if (top)
454 {
455 /* The stack pointer of a frame is known: mark the part of the stack
456 above it conservatively. This includes any outgoing arguments. */
457 mark_memory (top + 1, fp);
458 /* Mark the rest of the stack precisely. */
459 mark_objects (frame_base, top + 1 - frame_base);
460 }
461 else
462 {
463 /* The stack pointer is unknown -- mark everything conservatively. */
464 mark_memory (frame_base, fp);
465 }
466 top = sf_get_lisp_ptr (fp, SFI_SAVED_TOP);
467 fp = next_fp;
468 }
469}
470
471DEFUN ("internal-stack-stats", Finternal_stack_stats, Sinternal_stack_stats,
472 0, 0, 0,
473 doc: /* internal */)
474 (void)
475{
476 struct bc_thread_state *bc = &current_thread->bc;
477 int nframes = 0;
478 int nruns = 0;
479 for (Lisp_Object *fp = bc->fp; fp; fp = sf_get_lisp_ptr (fp, SFI_SAVED_FP))
480 {
481 nframes++;
482 if (sf_get_lisp_ptr (fp, SFI_SAVED_TOP) == NULL)
483 nruns++;
484 }
485 fprintf (stderr, "%d stack frames, %d runs\n", nframes, nruns);
486 return Qnil;
487}
488
489/* Whether a stack pointer is valid in the current frame. */
490INLINE bool
491valid_sp (struct bc_thread_state *bc, Lisp_Object *sp)
492{
493 Lisp_Object *fp = bc->fp;
494 return sp < fp && sp + 1 >= sf_get_lisp_ptr (fp, SFI_SAVED_FP) + SF_SIZE;
495}
496
337/* Execute the byte-code in FUN. ARGS_TEMPLATE is the function arity 497/* Execute the byte-code in FUN. ARGS_TEMPLATE is the function arity
338 encoded as an integer (the one in FUN is ignored), and ARGS, of 498 encoded as an integer (the one in FUN is ignored), and ARGS, of
339 size NARGS, should be a vector of the actual arguments. The 499 size NARGS, should be a vector of the actual arguments. The
@@ -347,37 +507,49 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
347#ifdef BYTE_CODE_METER 507#ifdef BYTE_CODE_METER
348 int volatile this_op = 0; 508 int volatile this_op = 0;
349#endif 509#endif
510 unsigned char quitcounter = 1;
511 struct bc_thread_state *bc = &current_thread->bc;
512
513 /* Values used for the first stack record when called from C. */
514 Lisp_Object *top = NULL;
515 unsigned char const *pc = NULL;
350 516
351 Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE); 517 Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE);
352 518
519 setup_frame: ;
353 eassert (!STRING_MULTIBYTE (bytestr)); 520 eassert (!STRING_MULTIBYTE (bytestr));
354 eassert (string_immovable_p (bytestr)); 521 eassert (string_immovable_p (bytestr));
522 /* FIXME: in debug mode (!NDEBUG, BYTE_CODE_SAFE or enabled checking),
523 save the specpdl index on function entry and check that it is the same
524 when returning, to detect unwind imbalances. This would require adding
525 a field to the frame header. */
526
355 Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS); 527 Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS);
356 Lisp_Object maxdepth = AREF (fun, COMPILED_STACK_DEPTH); 528 Lisp_Object maxdepth = AREF (fun, COMPILED_STACK_DEPTH);
357 ptrdiff_t const_length = ASIZE (vector); 529 ptrdiff_t const_length = ASIZE (vector);
358 ptrdiff_t bytestr_length = SCHARS (bytestr); 530 ptrdiff_t bytestr_length = SCHARS (bytestr);
359 Lisp_Object *vectorp = XVECTOR (vector)->contents; 531 Lisp_Object *vectorp = XVECTOR (vector)->contents;
360 532
361 unsigned char quitcounter = 1; 533 EMACS_INT max_stack = XFIXNAT (maxdepth);
362 /* Allocate two more slots than required, because... */ 534 Lisp_Object *frame_base = bc->fp + SF_SIZE;
363 EMACS_INT stack_items = XFIXNAT (maxdepth) + 2; 535 Lisp_Object *fp = frame_base + max_stack;
364 USE_SAFE_ALLOCA; 536
365 void *alloc; 537 if (fp + SF_SIZE > bc->stack_end)
366 SAFE_ALLOCA_LISP (alloc, stack_items); 538 error ("Bytecode stack overflow");
367 Lisp_Object *stack_base = alloc; 539
368 /* ... we plonk BYTESTR and VECTOR there to ensure that they survive 540 /* Save the function object so that the bytecode and vector are
369 GC (bug#33014), since these variables aren't used directly beyond 541 held from removal by the GC. */
370 the interpreter prologue and wouldn't be found in the stack frame 542 fp[SFI_FUN] = fun;
371 otherwise. */ 543 /* Save previous stack pointer and pc in the new frame. If we came
372 stack_base[0] = bytestr; 544 directly from outside, these will be NULL. */
373 stack_base[1] = vector; 545 sf_set_lisp_ptr (fp, SFI_SAVED_TOP, top);
374 Lisp_Object *top = stack_base + 1; 546 sf_set_saved_pc (fp, pc);
375 Lisp_Object *stack_lim = top + stack_items; 547 sf_set_lisp_ptr (fp, SFI_SAVED_FP, bc->fp);
548 bc->fp = fp;
549
550 top = frame_base - 1;
376 unsigned char const *bytestr_data = SDATA (bytestr); 551 unsigned char const *bytestr_data = SDATA (bytestr);
377 unsigned char const *pc = bytestr_data; 552 pc = bytestr_data;
378#if BYTE_CODE_SAFE || !defined NDEBUG
379 specpdl_ref count = SPECPDL_INDEX ();
380#endif
381 553
382 /* ARGS_TEMPLATE is composed of bit fields: 554 /* ARGS_TEMPLATE is composed of bit fields:
383 bits 0..6 minimum number of arguments 555 bits 0..6 minimum number of arguments
@@ -404,7 +576,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
404 int op; 576 int op;
405 enum handlertype type; 577 enum handlertype type;
406 578
407 if (BYTE_CODE_SAFE && ! (stack_base <= top && top < stack_lim)) 579 if (BYTE_CODE_SAFE && !valid_sp (bc, top))
408 emacs_abort (); 580 emacs_abort ();
409 581
410#ifdef BYTE_CODE_METER 582#ifdef BYTE_CODE_METER
@@ -636,36 +808,45 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
636 error ("Lisp nesting exceeds `max-lisp-eval-depth'"); 808 error ("Lisp nesting exceeds `max-lisp-eval-depth'");
637 } 809 }
638 810
639 ptrdiff_t numargs = op; 811 ptrdiff_t call_nargs = op;
640 Lisp_Object fun = TOP; 812 Lisp_Object call_fun = TOP;
641 Lisp_Object *args = &TOP + 1; 813 Lisp_Object *call_args = &TOP + 1;
642 814
643 specpdl_ref count1 = record_in_backtrace (fun, args, numargs); 815 specpdl_ref count1 = record_in_backtrace (call_fun,
816 call_args, call_nargs);
644 maybe_gc (); 817 maybe_gc ();
645 if (debug_on_next_call) 818 if (debug_on_next_call)
646 do_debug_on_call (Qlambda, count1); 819 do_debug_on_call (Qlambda, count1);
647 820
648 Lisp_Object original_fun = fun; 821 Lisp_Object original_fun = call_fun;
649 if (SYMBOLP (fun)) 822 if (SYMBOLP (call_fun))
650 fun = XSYMBOL (fun)->u.s.function; 823 call_fun = XSYMBOL (call_fun)->u.s.function;
651 Lisp_Object template; 824 Lisp_Object template;
652 Lisp_Object bytecode; 825 Lisp_Object bytecode;
653 Lisp_Object val; 826 if (COMPILEDP (call_fun)
654 if (COMPILEDP (fun)
655 // Lexical binding only. 827 // Lexical binding only.
656 && (template = AREF (fun, COMPILED_ARGLIST), 828 && (template = AREF (call_fun, COMPILED_ARGLIST),
657 FIXNUMP (template)) 829 FIXNUMP (template))
658 // No autoloads. 830 // No autoloads.
659 && (bytecode = AREF (fun, COMPILED_BYTECODE), 831 && (bytecode = AREF (call_fun, COMPILED_BYTECODE),
660 !CONSP (bytecode))) 832 !CONSP (bytecode)))
661 val = exec_byte_code (fun, XFIXNUM (template), numargs, args); 833 {
662 else if (SUBRP (fun) && !SUBR_NATIVE_COMPILED_DYNP (fun)) 834 fun = call_fun;
663 val = funcall_subr (XSUBR (fun), numargs, args); 835 bytestr = bytecode;
836 args_template = XFIXNUM (template);
837 nargs = call_nargs;
838 args = call_args;
839 goto setup_frame;
840 }
841
842 Lisp_Object val;
843 if (SUBRP (call_fun) && !SUBR_NATIVE_COMPILED_DYNP (call_fun))
844 val = funcall_subr (XSUBR (call_fun), call_nargs, call_args);
664 else 845 else
665 val = funcall_general (original_fun, numargs, args); 846 val = funcall_general (original_fun, call_nargs, call_args);
666 847
667 lisp_eval_depth--; 848 lisp_eval_depth--;
668 if (backtrace_debug_on_exit (specpdl_ref_to_ptr (count1))) 849 if (backtrace_debug_on_exit (specpdl_ptr - 1))
669 val = call_debugger (list2 (Qexit, val)); 850 val = call_debugger (list2 (Qexit, val));
670 specpdl_ptr--; 851 specpdl_ptr--;
671 852
@@ -731,7 +912,40 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
731 NEXT; 912 NEXT;
732 913
733 CASE (Breturn): 914 CASE (Breturn):
734 goto exit; 915 {
916 Lisp_Object *saved_top = sf_get_lisp_ptr (bc->fp, SFI_SAVED_TOP);
917 if (saved_top)
918 {
919 Lisp_Object val = TOP;
920
921 lisp_eval_depth--;
922 if (backtrace_debug_on_exit (specpdl_ptr - 1))
923 val = call_debugger (list2 (Qexit, val));
924 specpdl_ptr--;
925
926 top = saved_top;
927 pc = sf_get_saved_pc (bc->fp);
928 Lisp_Object *fp = sf_get_lisp_ptr (bc->fp, SFI_SAVED_FP);
929 bc->fp = fp;
930
931 Lisp_Object fun = fp[SFI_FUN];
932 Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE);
933 Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS);
934 bytestr_data = SDATA (bytestr);
935 vectorp = XVECTOR (vector)->contents;
936 if (BYTE_CODE_SAFE)
937 {
938 /* Only required for checking, not for execution. */
939 const_length = ASIZE (vector);
940 bytestr_length = SCHARS (bytestr);
941 }
942
943 TOP = val;
944 NEXT;
945 }
946 else
947 goto exit;
948 }
735 949
736 CASE (Bdiscard): 950 CASE (Bdiscard):
737 DISCARD (1); 951 DISCARD (1);
@@ -786,9 +1000,23 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
786 if (sys_setjmp (c->jmp)) 1000 if (sys_setjmp (c->jmp))
787 { 1001 {
788 struct handler *c = handlerlist; 1002 struct handler *c = handlerlist;
1003 handlerlist = c->next;
789 top = c->bytecode_top; 1004 top = c->bytecode_top;
790 op = c->bytecode_dest; 1005 op = c->bytecode_dest;
791 handlerlist = c->next; 1006 Lisp_Object *fp = bc->fp;
1007
1008 Lisp_Object fun = fp[SFI_FUN];
1009 Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE);
1010 Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS);
1011 bytestr_data = SDATA (bytestr);
1012 vectorp = XVECTOR (vector)->contents;
1013 if (BYTE_CODE_SAFE)
1014 {
1015 /* Only required for checking, not for execution. */
1016 const_length = ASIZE (vector);
1017 bytestr_length = SCHARS (bytestr);
1018 }
1019 pc = bytestr_data;
792 PUSH (c->val); 1020 PUSH (c->val);
793 goto op_branch; 1021 goto op_branch;
794 } 1022 }
@@ -1527,20 +1755,9 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
1527 1755
1528 exit: 1756 exit:
1529 1757
1530#if BYTE_CODE_SAFE || !defined NDEBUG 1758 bc->fp = sf_get_lisp_ptr (bc->fp, SFI_SAVED_FP);
1531 if (!specpdl_ref_eq (SPECPDL_INDEX (), count))
1532 {
1533 /* Binds and unbinds are supposed to be compiled balanced. */
1534 if (specpdl_ref_lt (count, SPECPDL_INDEX ()))
1535 unbind_to (count, Qnil);
1536 error ("binding stack not balanced (serious byte compiler bug)");
1537 }
1538#endif
1539 /* The byte code should have been properly pinned. */
1540 eassert (SDATA (bytestr) == bytestr_data);
1541 1759
1542 Lisp_Object result = TOP; 1760 Lisp_Object result = TOP;
1543 SAFE_FREE ();
1544 return result; 1761 return result;
1545} 1762}
1546 1763
@@ -1562,6 +1779,7 @@ void
1562syms_of_bytecode (void) 1779syms_of_bytecode (void)
1563{ 1780{
1564 defsubr (&Sbyte_code); 1781 defsubr (&Sbyte_code);
1782 defsubr (&Sinternal_stack_stats);
1565 1783
1566#ifdef BYTE_CODE_METER 1784#ifdef BYTE_CODE_METER
1567 1785