aboutsummaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/alloc.c2
-rw-r--r--src/bytecode.c318
-rw-r--r--src/eval.c2
-rw-r--r--src/lisp.h17
-rw-r--r--src/thread.c6
-rw-r--r--src/thread.h9
6 files changed, 303 insertions, 51 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 9ed94dc8a1e..c19e3dabb6e 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -4928,7 +4928,7 @@ mark_maybe_pointer (void *p, bool symbol_only)
4928/* Mark Lisp objects referenced from the address range START..END 4928/* Mark Lisp objects referenced from the address range START..END
4929 or END..START. */ 4929 or END..START. */
4930 4930
4931static void ATTRIBUTE_NO_SANITIZE_ADDRESS 4931void ATTRIBUTE_NO_SANITIZE_ADDRESS
4932mark_memory (void const *start, void const *end) 4932mark_memory (void const *start, void const *end)
4933{ 4933{
4934 char const *pp; 4934 char const *pp;
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
diff --git a/src/eval.c b/src/eval.c
index b1c1a8c676b..c46b74ac40c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1233,6 +1233,7 @@ unwind_to_catch (struct handler *catch, enum nonlocal_exit type,
1233 eassert (handlerlist == catch); 1233 eassert (handlerlist == catch);
1234 1234
1235 lisp_eval_depth = catch->f_lisp_eval_depth; 1235 lisp_eval_depth = catch->f_lisp_eval_depth;
1236 set_act_rec (current_thread, catch->act_rec);
1236 1237
1237 sys_longjmp (catch->jmp, 1); 1238 sys_longjmp (catch->jmp, 1);
1238} 1239}
@@ -1673,6 +1674,7 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
1673 c->next = handlerlist; 1674 c->next = handlerlist;
1674 c->f_lisp_eval_depth = lisp_eval_depth; 1675 c->f_lisp_eval_depth = lisp_eval_depth;
1675 c->pdlcount = SPECPDL_INDEX (); 1676 c->pdlcount = SPECPDL_INDEX ();
1677 c->act_rec = get_act_rec (current_thread);
1676 c->poll_suppress_count = poll_suppress_count; 1678 c->poll_suppress_count = poll_suppress_count;
1677 c->interrupt_input_blocked = interrupt_input_blocked; 1679 c->interrupt_input_blocked = interrupt_input_blocked;
1678 handlerlist = c; 1680 handlerlist = c;
diff --git a/src/lisp.h b/src/lisp.h
index 5e3590675d1..8053bbc9777 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3546,6 +3546,7 @@ struct handler
3546 sys_jmp_buf jmp; 3546 sys_jmp_buf jmp;
3547 EMACS_INT f_lisp_eval_depth; 3547 EMACS_INT f_lisp_eval_depth;
3548 specpdl_ref pdlcount; 3548 specpdl_ref pdlcount;
3549 Lisp_Object *act_rec;
3549 int poll_suppress_count; 3550 int poll_suppress_count;
3550 int interrupt_input_blocked; 3551 int interrupt_input_blocked;
3551}; 3552};
@@ -4087,6 +4088,7 @@ extern void alloc_unexec_pre (void);
4087extern void alloc_unexec_post (void); 4088extern void alloc_unexec_post (void);
4088extern void mark_stack (char const *, char const *); 4089extern void mark_stack (char const *, char const *);
4089extern void flush_stack_call_func1 (void (*func) (void *arg), void *arg); 4090extern void flush_stack_call_func1 (void (*func) (void *arg), void *arg);
4091extern void mark_memory (void const *start, void const *end);
4090 4092
4091/* Force callee-saved registers and register windows onto the stack, 4093/* Force callee-saved registers and register windows onto the stack,
4092 so that conservative garbage collection can see their values. */ 4094 so that conservative garbage collection can see their values. */
@@ -4855,6 +4857,21 @@ extern void syms_of_bytecode (void);
4855extern Lisp_Object exec_byte_code (Lisp_Object, ptrdiff_t, 4857extern Lisp_Object exec_byte_code (Lisp_Object, ptrdiff_t,
4856 ptrdiff_t, Lisp_Object *); 4858 ptrdiff_t, Lisp_Object *);
4857extern Lisp_Object get_byte_code_arity (Lisp_Object); 4859extern Lisp_Object get_byte_code_arity (Lisp_Object);
4860extern void init_bc_thread (struct bc_thread_state *bc);
4861extern void free_bc_thread (struct bc_thread_state *bc);
4862extern void mark_bytecode (struct bc_thread_state *bc);
4863
4864INLINE Lisp_Object *
4865get_act_rec (struct thread_state *th)
4866{
4867 return th->bc.fp;
4868}
4869
4870INLINE void
4871set_act_rec (struct thread_state *th, Lisp_Object *act_rec)
4872{
4873 th->bc.fp = act_rec;
4874}
4858 4875
4859/* Defined in macros.c. */ 4876/* Defined in macros.c. */
4860extern void init_macros (void); 4877extern void init_macros (void);
diff --git a/src/thread.c b/src/thread.c
index b5b7d7c0d71..c6742341fb8 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -671,6 +671,8 @@ mark_one_thread (struct thread_state *thread)
671 mark_object (tem); 671 mark_object (tem);
672 } 672 }
673 673
674 mark_bytecode (&thread->bc);
675
674 /* No need to mark Lisp_Object members like m_last_thing_searched, 676 /* No need to mark Lisp_Object members like m_last_thing_searched,
675 as mark_threads_callback does that by calling mark_object. */ 677 as mark_threads_callback does that by calling mark_object. */
676} 678}
@@ -839,6 +841,7 @@ finalize_one_thread (struct thread_state *state)
839 free_search_regs (&state->m_search_regs); 841 free_search_regs (&state->m_search_regs);
840 free_search_regs (&state->m_saved_search_regs); 842 free_search_regs (&state->m_saved_search_regs);
841 sys_cond_destroy (&state->thread_condvar); 843 sys_cond_destroy (&state->thread_condvar);
844 free_bc_thread (&state->bc);
842} 845}
843 846
844DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0, 847DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0,
@@ -868,6 +871,8 @@ If NAME is given, it must be a string; it names the new thread. */)
868 new_thread->m_specpdl_end = new_thread->m_specpdl + size; 871 new_thread->m_specpdl_end = new_thread->m_specpdl + size;
869 new_thread->m_specpdl_ptr = new_thread->m_specpdl; 872 new_thread->m_specpdl_ptr = new_thread->m_specpdl;
870 873
874 init_bc_thread (&new_thread->bc);
875
871 sys_cond_init (&new_thread->thread_condvar); 876 sys_cond_init (&new_thread->thread_condvar);
872 877
873 /* We'll need locking here eventually. */ 878 /* We'll need locking here eventually. */
@@ -1127,6 +1132,7 @@ init_threads (void)
1127 sys_mutex_lock (&global_lock); 1132 sys_mutex_lock (&global_lock);
1128 current_thread = &main_thread.s; 1133 current_thread = &main_thread.s;
1129 main_thread.s.thread_id = sys_thread_self (); 1134 main_thread.s.thread_id = sys_thread_self ();
1135 init_bc_thread (&main_thread.s.bc);
1130} 1136}
1131 1137
1132void 1138void
diff --git a/src/thread.h b/src/thread.h
index f2755045b2e..a29af702d13 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -33,6 +33,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
33#include "sysselect.h" /* FIXME */ 33#include "sysselect.h" /* FIXME */
34#include "systhread.h" 34#include "systhread.h"
35 35
36/* Byte-code interpreter thread state. */
37struct bc_thread_state {
38 Lisp_Object *fp; /* current frame pointer (see bytecode.c) */
39 Lisp_Object *stack;
40 Lisp_Object *stack_end;
41};
42
36struct thread_state 43struct thread_state
37{ 44{
38 union vectorlike_header header; 45 union vectorlike_header header;
@@ -181,6 +188,8 @@ struct thread_state
181 188
182 /* Threads are kept on a linked list. */ 189 /* Threads are kept on a linked list. */
183 struct thread_state *next_thread; 190 struct thread_state *next_thread;
191
192 struct bc_thread_state bc;
184} GCALIGNED_STRUCT; 193} GCALIGNED_STRUCT;
185 194
186INLINE bool 195INLINE bool