diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 2 | ||||
| -rw-r--r-- | src/bytecode.c | 318 | ||||
| -rw-r--r-- | src/eval.c | 2 | ||||
| -rw-r--r-- | src/lisp.h | 17 | ||||
| -rw-r--r-- | src/thread.c | 6 | ||||
| -rw-r--r-- | src/thread.h | 9 |
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 | ||
| 4931 | static void ATTRIBUTE_NO_SANITIZE_ADDRESS | 4931 | void ATTRIBUTE_NO_SANITIZE_ADDRESS |
| 4932 | mark_memory (void const *start, void const *end) | 4932 | mark_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. */ | ||
| 338 | enum 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 | |||
| 387 | INLINE void * | ||
| 388 | sf_get_ptr (Lisp_Object *fp, enum stack_frame_index index) | ||
| 389 | { | ||
| 390 | return XLP (fp[index]); | ||
| 391 | } | ||
| 392 | |||
| 393 | INLINE void | ||
| 394 | sf_set_ptr (Lisp_Object *fp, enum stack_frame_index index, void *value) | ||
| 395 | { | ||
| 396 | fp[index] = XIL ((EMACS_INT)value); | ||
| 397 | } | ||
| 398 | |||
| 399 | INLINE Lisp_Object * | ||
| 400 | sf_get_lisp_ptr (Lisp_Object *fp, enum stack_frame_index index) | ||
| 401 | { | ||
| 402 | return sf_get_ptr (fp, index); | ||
| 403 | } | ||
| 404 | |||
| 405 | INLINE void | ||
| 406 | sf_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 | |||
| 412 | INLINE const unsigned char * | ||
| 413 | sf_get_saved_pc (Lisp_Object *fp) | ||
| 414 | { | ||
| 415 | return sf_get_ptr (fp, SFI_SAVED_PC); | ||
| 416 | } | ||
| 417 | |||
| 418 | INLINE void | ||
| 419 | sf_set_saved_pc (Lisp_Object *fp, const unsigned char *value) | ||
| 420 | { | ||
| 421 | sf_set_ptr (fp, SFI_SAVED_PC, (unsigned char *)value); | ||
| 422 | } | ||
| 423 | |||
| 424 | void | ||
| 425 | init_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 | |||
| 434 | void | ||
| 435 | free_bc_thread (struct bc_thread_state *bc) | ||
| 436 | { | ||
| 437 | xfree (bc->stack); | ||
| 438 | } | ||
| 439 | |||
| 440 | void | ||
| 441 | mark_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 | |||
| 471 | DEFUN ("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 = ¤t_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. */ | ||
| 490 | INLINE bool | ||
| 491 | valid_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 = ¤t_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 | |||
| 1562 | syms_of_bytecode (void) | 1779 | syms_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); | |||
| 4087 | extern void alloc_unexec_post (void); | 4088 | extern void alloc_unexec_post (void); |
| 4088 | extern void mark_stack (char const *, char const *); | 4089 | extern void mark_stack (char const *, char const *); |
| 4089 | extern void flush_stack_call_func1 (void (*func) (void *arg), void *arg); | 4090 | extern void flush_stack_call_func1 (void (*func) (void *arg), void *arg); |
| 4091 | extern 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); | |||
| 4855 | extern Lisp_Object exec_byte_code (Lisp_Object, ptrdiff_t, | 4857 | extern Lisp_Object exec_byte_code (Lisp_Object, ptrdiff_t, |
| 4856 | ptrdiff_t, Lisp_Object *); | 4858 | ptrdiff_t, Lisp_Object *); |
| 4857 | extern Lisp_Object get_byte_code_arity (Lisp_Object); | 4859 | extern Lisp_Object get_byte_code_arity (Lisp_Object); |
| 4860 | extern void init_bc_thread (struct bc_thread_state *bc); | ||
| 4861 | extern void free_bc_thread (struct bc_thread_state *bc); | ||
| 4862 | extern void mark_bytecode (struct bc_thread_state *bc); | ||
| 4863 | |||
| 4864 | INLINE Lisp_Object * | ||
| 4865 | get_act_rec (struct thread_state *th) | ||
| 4866 | { | ||
| 4867 | return th->bc.fp; | ||
| 4868 | } | ||
| 4869 | |||
| 4870 | INLINE void | ||
| 4871 | set_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. */ |
| 4860 | extern void init_macros (void); | 4877 | extern 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 | ||
| 844 | DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0, | 847 | DEFUN ("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 | ||
| 1132 | void | 1138 | void |
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. */ | ||
| 37 | struct bc_thread_state { | ||
| 38 | Lisp_Object *fp; /* current frame pointer (see bytecode.c) */ | ||
| 39 | Lisp_Object *stack; | ||
| 40 | Lisp_Object *stack_end; | ||
| 41 | }; | ||
| 42 | |||
| 36 | struct thread_state | 43 | struct 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 | ||
| 186 | INLINE bool | 195 | INLINE bool |