diff options
Diffstat (limited to 'src/bytecode.c')
| -rw-r--r-- | src/bytecode.c | 318 |
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. */ | ||
| 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 | ||