diff options
| author | Mattias EngdegÄrd | 2022-03-14 12:57:29 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2022-03-17 16:38:22 +0100 |
| commit | 751c8f88c4faddb2b4f5d5ba3f051e8cd2c0153c (patch) | |
| tree | 73078523cc6c2343db46ff45c8189e1d75055c9a /src/bytecode.c | |
| parent | edb28bf669b890b7498cad0fd818ffa38b5e13a9 (diff) | |
| download | emacs-751c8f88c4faddb2b4f5d5ba3f051e8cd2c0153c.tar.gz emacs-751c8f88c4faddb2b4f5d5ba3f051e8cd2c0153c.zip | |
Put bytecode stack frame metadata in a struct
Using a plain C struct instead of type-punning Lisp_Object stack slots
makes the bytecode interpreter code more type-safe and potentially
faster (from better alias analysis), and the special-purpose accessors
are no longer needed. It also reduces the stack requirements when
using 64-bit Lisp_Object on 32-bit platforms.
* src/bytecode.c (enum stack_frame_index)
(sf_get_ptr, sf_set_ptr, sf_get_lisp_ptr, sf_set_lisp_ptr,
sf_get_saved_pc, sf_set_saved_pc): Remove.
(BC_STACK_SIZE): Now in bytes, not Lisp words.
(struct bc_frame): New.
(init_bc_thread, mark_bytecode, Finternal_stack_stats, valid_sp)
(exec_byte_code):
* src/lisp.h (struct handler, get_act_rec, set_act_rec):
Adapt to new struct bc_frame.
Diffstat (limited to 'src/bytecode.c')
| -rw-r--r-- | src/bytecode.c | 112 |
1 files changed, 38 insertions, 74 deletions
diff --git a/src/bytecode.c b/src/bytecode.c index 65c3ad4da70..ed1f6ca4a85 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -335,20 +335,7 @@ bcall0 (Lisp_Object f) | |||
| 335 | Ffuncall (1, &f); | 335 | Ffuncall (1, &f); |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | /* Layout of the stack frame header. */ | 338 | /* The bytecode stack size in bytes. |
| 339 | enum stack_frame_index { | ||
| 340 | SFI_SAVED_FP, /* previous frame pointer */ | ||
| 341 | |||
| 342 | /* In a frame called directly from C, the following two members are NULL. */ | ||
| 343 | SFI_SAVED_TOP, /* previous stack pointer */ | ||
| 344 | SFI_SAVED_PC, /* previous program counter */ | ||
| 345 | |||
| 346 | SFI_FUN, /* current function object */ | ||
| 347 | |||
| 348 | SF_SIZE /* number of words in the header */ | ||
| 349 | }; | ||
| 350 | |||
| 351 | /* The bytecode stack size in Lisp words. | ||
| 352 | This is a fairly generous amount, but: | 339 | This is a fairly generous amount, but: |
| 353 | - if users need more, we could allocate more, or just reserve the address | 340 | - if users need more, we could allocate more, or just reserve the address |
| 354 | space and allocate on demand | 341 | space and allocate on demand |
| @@ -357,7 +344,7 @@ enum stack_frame_index { | |||
| 357 | - for maximum flexibility but a small runtime penalty, we could allocate | 344 | - for maximum flexibility but a small runtime penalty, we could allocate |
| 358 | the stack in smaller chunks as needed | 345 | the stack in smaller chunks as needed |
| 359 | */ | 346 | */ |
| 360 | #define BC_STACK_SIZE (512 * 1024) | 347 | #define BC_STACK_SIZE (512 * 1024 * sizeof (Lisp_Object)) |
| 361 | 348 | ||
| 362 | /* Bytecode interpreter stack: | 349 | /* Bytecode interpreter stack: |
| 363 | 350 | ||
| @@ -385,51 +372,28 @@ enum stack_frame_index { | |||
| 385 | : : | 372 | : : |
| 386 | */ | 373 | */ |
| 387 | 374 | ||
| 388 | INLINE void * | 375 | /* bytecode stack frame header (footer, actually) */ |
| 389 | sf_get_ptr (Lisp_Object *fp, enum stack_frame_index index) | 376 | struct bc_frame { |
| 390 | { | 377 | struct bc_frame *saved_fp; /* previous frame pointer, |
| 391 | return XLP (fp[index]); | 378 | NULL if bottommost frame */ |
| 392 | } | ||
| 393 | |||
| 394 | INLINE void | ||
| 395 | sf_set_ptr (Lisp_Object *fp, enum stack_frame_index index, void *value) | ||
| 396 | { | ||
| 397 | fp[index] = XIL ((uintptr_t)value); | ||
| 398 | } | ||
| 399 | |||
| 400 | INLINE Lisp_Object * | ||
| 401 | sf_get_lisp_ptr (Lisp_Object *fp, enum stack_frame_index index) | ||
| 402 | { | ||
| 403 | return sf_get_ptr (fp, index); | ||
| 404 | } | ||
| 405 | 379 | ||
| 406 | INLINE void | 380 | /* In a frame called directly from C, the following two members are NULL. */ |
| 407 | sf_set_lisp_ptr (Lisp_Object *fp, enum stack_frame_index index, | 381 | Lisp_Object *saved_top; /* previous stack pointer */ |
| 408 | Lisp_Object *value) | 382 | const unsigned char *saved_pc; /* previous program counter */ |
| 409 | { | ||
| 410 | sf_set_ptr (fp, index, value); | ||
| 411 | } | ||
| 412 | 383 | ||
| 413 | INLINE const unsigned char * | 384 | Lisp_Object fun; /* current function object */ |
| 414 | sf_get_saved_pc (Lisp_Object *fp) | ||
| 415 | { | ||
| 416 | return sf_get_ptr (fp, SFI_SAVED_PC); | ||
| 417 | } | ||
| 418 | 385 | ||
| 419 | INLINE void | 386 | Lisp_Object next_stack[]; /* data stack of next frame */ |
| 420 | sf_set_saved_pc (Lisp_Object *fp, const unsigned char *value) | 387 | }; |
| 421 | { | ||
| 422 | sf_set_ptr (fp, SFI_SAVED_PC, (unsigned char *)value); | ||
| 423 | } | ||
| 424 | 388 | ||
| 425 | void | 389 | void |
| 426 | init_bc_thread (struct bc_thread_state *bc) | 390 | init_bc_thread (struct bc_thread_state *bc) |
| 427 | { | 391 | { |
| 428 | bc->stack = xmalloc (BC_STACK_SIZE * sizeof *bc->stack); | 392 | bc->stack = xmalloc (BC_STACK_SIZE); |
| 429 | bc->stack_end = bc->stack + BC_STACK_SIZE; | 393 | bc->stack_end = bc->stack + BC_STACK_SIZE; |
| 430 | /* Put a dummy header at the bottom to indicate the first free location. */ | 394 | /* Put a dummy header at the bottom to indicate the first free location. */ |
| 431 | bc->fp = bc->stack; | 395 | bc->fp = (struct bc_frame *)bc->stack; |
| 432 | memset (bc->fp, 0, SF_SIZE * sizeof *bc->stack); | 396 | memset (bc->fp, 0, sizeof *bc->fp); |
| 433 | } | 397 | } |
| 434 | 398 | ||
| 435 | void | 399 | void |
| @@ -441,16 +405,16 @@ free_bc_thread (struct bc_thread_state *bc) | |||
| 441 | void | 405 | void |
| 442 | mark_bytecode (struct bc_thread_state *bc) | 406 | mark_bytecode (struct bc_thread_state *bc) |
| 443 | { | 407 | { |
| 444 | Lisp_Object *fp = bc->fp; | 408 | struct bc_frame *fp = bc->fp; |
| 445 | Lisp_Object *top = NULL; /* stack pointer of topmost frame not known */ | 409 | Lisp_Object *top = NULL; /* stack pointer of topmost frame not known */ |
| 446 | for (;;) | 410 | for (;;) |
| 447 | { | 411 | { |
| 448 | Lisp_Object *next_fp = sf_get_lisp_ptr (fp, SFI_SAVED_FP); | 412 | struct bc_frame *next_fp = fp->saved_fp; |
| 449 | /* Only the dummy frame at the bottom has saved_fp = NULL. */ | 413 | /* Only the dummy frame at the bottom has saved_fp = NULL. */ |
| 450 | if (!next_fp) | 414 | if (!next_fp) |
| 451 | break; | 415 | break; |
| 452 | mark_object (fp[SFI_FUN]); | 416 | mark_object (fp->fun); |
| 453 | Lisp_Object *frame_base = next_fp + SF_SIZE; | 417 | Lisp_Object *frame_base = next_fp->next_stack; |
| 454 | if (top) | 418 | if (top) |
| 455 | { | 419 | { |
| 456 | /* The stack pointer of a frame is known: mark the part of the stack | 420 | /* The stack pointer of a frame is known: mark the part of the stack |
| @@ -464,7 +428,7 @@ mark_bytecode (struct bc_thread_state *bc) | |||
| 464 | /* The stack pointer is unknown -- mark everything conservatively. */ | 428 | /* The stack pointer is unknown -- mark everything conservatively. */ |
| 465 | mark_memory (frame_base, fp); | 429 | mark_memory (frame_base, fp); |
| 466 | } | 430 | } |
| 467 | top = sf_get_lisp_ptr (fp, SFI_SAVED_TOP); | 431 | top = fp->saved_top; |
| 468 | fp = next_fp; | 432 | fp = next_fp; |
| 469 | } | 433 | } |
| 470 | } | 434 | } |
| @@ -477,10 +441,10 @@ DEFUN ("internal-stack-stats", Finternal_stack_stats, Sinternal_stack_stats, | |||
| 477 | struct bc_thread_state *bc = ¤t_thread->bc; | 441 | struct bc_thread_state *bc = ¤t_thread->bc; |
| 478 | int nframes = 0; | 442 | int nframes = 0; |
| 479 | int nruns = 0; | 443 | int nruns = 0; |
| 480 | for (Lisp_Object *fp = bc->fp; fp; fp = sf_get_lisp_ptr (fp, SFI_SAVED_FP)) | 444 | for (struct bc_frame *fp = bc->fp; fp; fp = fp->saved_fp) |
| 481 | { | 445 | { |
| 482 | nframes++; | 446 | nframes++; |
| 483 | if (sf_get_lisp_ptr (fp, SFI_SAVED_TOP) == NULL) | 447 | if (fp->saved_top == NULL) |
| 484 | nruns++; | 448 | nruns++; |
| 485 | } | 449 | } |
| 486 | fprintf (stderr, "%d stack frames, %d runs\n", nframes, nruns); | 450 | fprintf (stderr, "%d stack frames, %d runs\n", nframes, nruns); |
| @@ -491,8 +455,8 @@ DEFUN ("internal-stack-stats", Finternal_stack_stats, Sinternal_stack_stats, | |||
| 491 | INLINE bool | 455 | INLINE bool |
| 492 | valid_sp (struct bc_thread_state *bc, Lisp_Object *sp) | 456 | valid_sp (struct bc_thread_state *bc, Lisp_Object *sp) |
| 493 | { | 457 | { |
| 494 | Lisp_Object *fp = bc->fp; | 458 | struct bc_frame *fp = bc->fp; |
| 495 | return sp < fp && sp + 1 >= sf_get_lisp_ptr (fp, SFI_SAVED_FP) + SF_SIZE; | 459 | return sp < (Lisp_Object *)fp && sp + 1 >= fp->saved_fp->next_stack; |
| 496 | } | 460 | } |
| 497 | 461 | ||
| 498 | /* Execute the byte-code in FUN. ARGS_TEMPLATE is the function arity | 462 | /* Execute the byte-code in FUN. ARGS_TEMPLATE is the function arity |
| @@ -532,20 +496,20 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template, | |||
| 532 | Lisp_Object *vectorp = XVECTOR (vector)->contents; | 496 | Lisp_Object *vectorp = XVECTOR (vector)->contents; |
| 533 | 497 | ||
| 534 | EMACS_INT max_stack = XFIXNAT (maxdepth); | 498 | EMACS_INT max_stack = XFIXNAT (maxdepth); |
| 535 | Lisp_Object *frame_base = bc->fp + SF_SIZE; | 499 | Lisp_Object *frame_base = bc->fp->next_stack; |
| 536 | Lisp_Object *fp = frame_base + max_stack; | 500 | struct bc_frame *fp = (struct bc_frame *)(frame_base + max_stack); |
| 537 | 501 | ||
| 538 | if (fp + SF_SIZE > bc->stack_end) | 502 | if ((char *)fp->next_stack > bc->stack_end) |
| 539 | error ("Bytecode stack overflow"); | 503 | error ("Bytecode stack overflow"); |
| 540 | 504 | ||
| 541 | /* Save the function object so that the bytecode and vector are | 505 | /* Save the function object so that the bytecode and vector are |
| 542 | held from removal by the GC. */ | 506 | held from removal by the GC. */ |
| 543 | fp[SFI_FUN] = fun; | 507 | fp->fun = fun; |
| 544 | /* Save previous stack pointer and pc in the new frame. If we came | 508 | /* Save previous stack pointer and pc in the new frame. If we came |
| 545 | directly from outside, these will be NULL. */ | 509 | directly from outside, these will be NULL. */ |
| 546 | sf_set_lisp_ptr (fp, SFI_SAVED_TOP, top); | 510 | fp->saved_top = top; |
| 547 | sf_set_saved_pc (fp, pc); | 511 | fp->saved_pc = pc; |
| 548 | sf_set_lisp_ptr (fp, SFI_SAVED_FP, bc->fp); | 512 | fp->saved_fp = bc->fp; |
| 549 | bc->fp = fp; | 513 | bc->fp = fp; |
| 550 | 514 | ||
| 551 | top = frame_base - 1; | 515 | top = frame_base - 1; |
| @@ -914,7 +878,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template, | |||
| 914 | 878 | ||
| 915 | CASE (Breturn): | 879 | CASE (Breturn): |
| 916 | { | 880 | { |
| 917 | Lisp_Object *saved_top = sf_get_lisp_ptr (bc->fp, SFI_SAVED_TOP); | 881 | Lisp_Object *saved_top = bc->fp->saved_top; |
| 918 | if (saved_top) | 882 | if (saved_top) |
| 919 | { | 883 | { |
| 920 | Lisp_Object val = TOP; | 884 | Lisp_Object val = TOP; |
| @@ -925,11 +889,11 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template, | |||
| 925 | specpdl_ptr--; | 889 | specpdl_ptr--; |
| 926 | 890 | ||
| 927 | top = saved_top; | 891 | top = saved_top; |
| 928 | pc = sf_get_saved_pc (bc->fp); | 892 | pc = bc->fp->saved_pc; |
| 929 | Lisp_Object *fp = sf_get_lisp_ptr (bc->fp, SFI_SAVED_FP); | 893 | struct bc_frame *fp = bc->fp->saved_fp; |
| 930 | bc->fp = fp; | 894 | bc->fp = fp; |
| 931 | 895 | ||
| 932 | Lisp_Object fun = fp[SFI_FUN]; | 896 | Lisp_Object fun = fp->fun; |
| 933 | Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE); | 897 | Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE); |
| 934 | Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS); | 898 | Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS); |
| 935 | bytestr_data = SDATA (bytestr); | 899 | bytestr_data = SDATA (bytestr); |
| @@ -1004,9 +968,9 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template, | |||
| 1004 | handlerlist = c->next; | 968 | handlerlist = c->next; |
| 1005 | top = c->bytecode_top; | 969 | top = c->bytecode_top; |
| 1006 | op = c->bytecode_dest; | 970 | op = c->bytecode_dest; |
| 1007 | Lisp_Object *fp = bc->fp; | 971 | struct bc_frame *fp = bc->fp; |
| 1008 | 972 | ||
| 1009 | Lisp_Object fun = fp[SFI_FUN]; | 973 | Lisp_Object fun = fp->fun; |
| 1010 | Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE); | 974 | Lisp_Object bytestr = AREF (fun, COMPILED_BYTECODE); |
| 1011 | Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS); | 975 | Lisp_Object vector = AREF (fun, COMPILED_CONSTANTS); |
| 1012 | bytestr_data = SDATA (bytestr); | 976 | bytestr_data = SDATA (bytestr); |
| @@ -1756,7 +1720,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template, | |||
| 1756 | 1720 | ||
| 1757 | exit: | 1721 | exit: |
| 1758 | 1722 | ||
| 1759 | bc->fp = sf_get_lisp_ptr (bc->fp, SFI_SAVED_FP); | 1723 | bc->fp = bc->fp->saved_fp; |
| 1760 | 1724 | ||
| 1761 | Lisp_Object result = TOP; | 1725 | Lisp_Object result = TOP; |
| 1762 | return result; | 1726 | return result; |