diff options
| author | Stefan Monnier | 2013-10-03 00:58:56 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-10-03 00:58:56 -0400 |
| commit | adf2aa61404305e58e71cde0193bb650aff2c4b3 (patch) | |
| tree | d6e6b4e5ab3b144a94daed2232cab798aadeb20a /src/lisp.h | |
| parent | 328a8179fec33f5a75e2cfe22e43f4ec0df770b7 (diff) | |
| download | emacs-adf2aa61404305e58e71cde0193bb650aff2c4b3.tar.gz emacs-adf2aa61404305e58e71cde0193bb650aff2c4b3.zip | |
Introduce new bytecodes for efficient catch/condition-case in lexbind.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Optimize under `condition-case' and `catch' if
byte-compile--use-old-handlers is nil.
(disassemble-offset): Handle new bytecodes.
* lisp/emacs-lisp/bytecomp.el (byte-pushcatch, byte-pushconditioncase)
(byte-pophandler): New byte codes.
(byte-goto-ops): Adjust accordingly.
(byte-compile--use-old-handlers): New var.
(byte-compile-catch): Use new byte codes depending on
byte-compile--use-old-handlers.
(byte-compile-condition-case--old): Rename from
byte-compile-condition-case.
(byte-compile-condition-case--new): New function.
(byte-compile-condition-case): New function that dispatches depending
on byte-compile--use-old-handlers.
(byte-compile-unwind-protect): Pass a function to byte-unwind-protect
when we can.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv-analyse-form): Adjust for
the new compilation scheme using the new byte-codes.
* src/alloc.c (Fgarbage_collect): Merge scans of handlerlist and catchlist,
and make them unconditional now that they're heap-allocated.
* src/bytecode.c (BYTE_CODES): Add Bpushcatch, Bpushconditioncase
and Bpophandler.
(bcall0): New function.
(exec_byte_code): Add corresponding cases. Improve error message when
encountering an invalid byte-code. Let Bunwind_protect accept
a function (rather than a list of expressions) as argument.
* src/eval.c (catchlist): Remove (merge with handlerlist).
(handlerlist, lisp_eval_depth): Not static any more.
(internal_catch, internal_condition_case, internal_condition_case_1)
(internal_condition_case_2, internal_condition_case_n):
Use PUSH_HANDLER.
(unwind_to_catch, Fthrow, Fsignal): Adjust to merged
handlerlist/catchlist.
(internal_lisp_condition_case): Use PUSH_HANDLER. Adjust to new
handlerlist which can only handle a single condition-case handler at
a time.
(find_handler_clause): Simplify since we only a single branch here
any more.
* src/lisp.h (struct handler): Merge struct handler and struct catchtag.
(PUSH_HANDLER): New macro.
(catchlist): Remove.
(handlerlist): Always declare.
Diffstat (limited to 'src/lisp.h')
| -rw-r--r-- | src/lisp.h | 111 |
1 files changed, 58 insertions, 53 deletions
diff --git a/src/lisp.h b/src/lisp.h index 63597e86be6..688c89c1eee 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2635,11 +2635,9 @@ typedef jmp_buf sys_jmp_buf; | |||
| 2635 | - The specpdl stack: keeps track of active unwind-protect and | 2635 | - The specpdl stack: keeps track of active unwind-protect and |
| 2636 | dynamic-let-bindings. Allocated from the `specpdl' array, a manually | 2636 | dynamic-let-bindings. Allocated from the `specpdl' array, a manually |
| 2637 | managed stack. | 2637 | managed stack. |
| 2638 | - The catch stack: keeps track of active catch tags. | 2638 | - The handler stack: keeps track of active catch tags and condition-case |
| 2639 | Allocated on the C stack. This is where the setmp data is kept. | 2639 | handlers. Allocated in a manually managed stack implemented by a |
| 2640 | - The handler stack: keeps track of active condition-case handlers. | 2640 | doubly-linked list allocated via xmalloc and never freed. */ |
| 2641 | Allocated on the C stack. Every entry there also uses an entry in | ||
| 2642 | the catch stack. */ | ||
| 2643 | 2641 | ||
| 2644 | /* Structure for recording Lisp call stack for backtrace purposes. */ | 2642 | /* Structure for recording Lisp call stack for backtrace purposes. */ |
| 2645 | 2643 | ||
| @@ -2709,46 +2707,16 @@ SPECPDL_INDEX (void) | |||
| 2709 | return specpdl_ptr - specpdl; | 2707 | return specpdl_ptr - specpdl; |
| 2710 | } | 2708 | } |
| 2711 | 2709 | ||
| 2712 | /* Everything needed to describe an active condition case. | 2710 | /* This structure helps implement the `catch/throw' and `condition-case/signal' |
| 2711 | control structures. A struct handler contains all the information needed to | ||
| 2712 | restore the state of the interpreter after a non-local jump. | ||
| 2713 | 2713 | ||
| 2714 | Members are volatile if their values need to survive _longjmp when | 2714 | handler structures are chained together in a doubly linked list; the `next' |
| 2715 | a 'struct handler' is a local variable. */ | 2715 | member points to the next outer catchtag and the `nextfree' member points in |
| 2716 | struct handler | 2716 | the other direction to the next inner element (which is typically the next |
| 2717 | { | 2717 | free element since we mostly use it on the deepest handler). |
| 2718 | /* The handler clauses and variable from the condition-case form. */ | ||
| 2719 | /* For a handler set up in Lisp code, this is always a list. | ||
| 2720 | For an internal handler set up by internal_condition_case*, | ||
| 2721 | this can instead be the symbol t or `error'. | ||
| 2722 | t: handle all conditions. | ||
| 2723 | error: handle all conditions, and errors can run the debugger | ||
| 2724 | or display a backtrace. */ | ||
| 2725 | Lisp_Object handler; | ||
| 2726 | |||
| 2727 | Lisp_Object volatile var; | ||
| 2728 | |||
| 2729 | /* Fsignal stores here the condition-case clause that applies, | ||
| 2730 | and Fcondition_case thus knows which clause to run. */ | ||
| 2731 | Lisp_Object volatile chosen_clause; | ||
| 2732 | |||
| 2733 | /* Used to effect the longjump out to the handler. */ | ||
| 2734 | struct catchtag *tag; | ||
| 2735 | |||
| 2736 | /* The next enclosing handler. */ | ||
| 2737 | struct handler *next; | ||
| 2738 | }; | ||
| 2739 | 2718 | ||
| 2740 | /* This structure helps implement the `catch' and `throw' control | 2719 | A call like (throw TAG VAL) searches for a catchtag whose `tag_or_ch' |
| 2741 | structure. A struct catchtag contains all the information needed | ||
| 2742 | to restore the state of the interpreter after a non-local jump. | ||
| 2743 | |||
| 2744 | Handlers for error conditions (represented by `struct handler' | ||
| 2745 | structures) just point to a catch tag to do the cleanup required | ||
| 2746 | for their jumps. | ||
| 2747 | |||
| 2748 | catchtag structures are chained together in the C calling stack; | ||
| 2749 | the `next' member points to the next outer catchtag. | ||
| 2750 | |||
| 2751 | A call like (throw TAG VAL) searches for a catchtag whose `tag' | ||
| 2752 | member is TAG, and then unbinds to it. The `val' member is used to | 2720 | member is TAG, and then unbinds to it. The `val' member is used to |
| 2753 | hold VAL while the stack is unwound; `val' is returned as the value | 2721 | hold VAL while the stack is unwound; `val' is returned as the value |
| 2754 | of the catch form. | 2722 | of the catch form. |
| @@ -2757,24 +2725,63 @@ struct handler | |||
| 2757 | state. | 2725 | state. |
| 2758 | 2726 | ||
| 2759 | Members are volatile if their values need to survive _longjmp when | 2727 | Members are volatile if their values need to survive _longjmp when |
| 2760 | a 'struct catchtag' is a local variable. */ | 2728 | a 'struct handler' is a local variable. */ |
| 2761 | struct catchtag | 2729 | |
| 2730 | enum handlertype { CATCHER, CONDITION_CASE }; | ||
| 2731 | |||
| 2732 | struct handler | ||
| 2762 | { | 2733 | { |
| 2763 | Lisp_Object tag; | 2734 | enum handlertype type; |
| 2764 | Lisp_Object volatile val; | 2735 | Lisp_Object tag_or_ch; |
| 2765 | struct catchtag *volatile next; | 2736 | Lisp_Object val; |
| 2737 | struct handler *next; | ||
| 2738 | struct handler *nextfree; | ||
| 2739 | |||
| 2740 | /* The bytecode interpreter can have several handlers active at the same | ||
| 2741 | time, so when we longjmp to one of them, it needs to know which handler | ||
| 2742 | this was and what was the corresponding internal state. This is stored | ||
| 2743 | here, and when we longjmp we make sure that handlerlist points to the | ||
| 2744 | proper handler. */ | ||
| 2745 | Lisp_Object *bytecode_top; | ||
| 2746 | int bytecode_dest; | ||
| 2747 | |||
| 2748 | /* Most global vars are reset to their value via the specpdl mechanism, | ||
| 2749 | but a few others are handled by storing their value here. */ | ||
| 2766 | #if 1 /* GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS, but they're defined later. */ | 2750 | #if 1 /* GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS, but they're defined later. */ |
| 2767 | struct gcpro *gcpro; | 2751 | struct gcpro *gcpro; |
| 2768 | #endif | 2752 | #endif |
| 2769 | sys_jmp_buf jmp; | 2753 | sys_jmp_buf jmp; |
| 2770 | struct handler *handlerlist; | ||
| 2771 | EMACS_INT lisp_eval_depth; | 2754 | EMACS_INT lisp_eval_depth; |
| 2772 | ptrdiff_t volatile pdlcount; | 2755 | ptrdiff_t pdlcount; |
| 2773 | int poll_suppress_count; | 2756 | int poll_suppress_count; |
| 2774 | int interrupt_input_blocked; | 2757 | int interrupt_input_blocked; |
| 2775 | struct byte_stack *byte_stack; | 2758 | struct byte_stack *byte_stack; |
| 2776 | }; | 2759 | }; |
| 2777 | 2760 | ||
| 2761 | /* Fill in the components of c, and put it on the list. */ | ||
| 2762 | #define PUSH_HANDLER(c, tag_ch_val, handlertype) \ | ||
| 2763 | if (handlerlist && handlerlist->nextfree) \ | ||
| 2764 | (c) = handlerlist->nextfree; \ | ||
| 2765 | else \ | ||
| 2766 | { \ | ||
| 2767 | (c) = xmalloc (sizeof (struct handler)); \ | ||
| 2768 | (c)->nextfree = NULL; \ | ||
| 2769 | if (handlerlist) \ | ||
| 2770 | handlerlist->nextfree = (c); \ | ||
| 2771 | } \ | ||
| 2772 | (c)->type = (handlertype); \ | ||
| 2773 | (c)->tag_or_ch = (tag_ch_val); \ | ||
| 2774 | (c)->val = Qnil; \ | ||
| 2775 | (c)->next = handlerlist; \ | ||
| 2776 | (c)->lisp_eval_depth = lisp_eval_depth; \ | ||
| 2777 | (c)->pdlcount = SPECPDL_INDEX (); \ | ||
| 2778 | (c)->poll_suppress_count = poll_suppress_count; \ | ||
| 2779 | (c)->interrupt_input_blocked = interrupt_input_blocked;\ | ||
| 2780 | (c)->gcpro = gcprolist; \ | ||
| 2781 | (c)->byte_stack = byte_stack_list; \ | ||
| 2782 | handlerlist = (c); | ||
| 2783 | |||
| 2784 | |||
| 2778 | extern Lisp_Object memory_signal_data; | 2785 | extern Lisp_Object memory_signal_data; |
| 2779 | 2786 | ||
| 2780 | /* An address near the bottom of the stack. | 2787 | /* An address near the bottom of the stack. |
| @@ -3677,10 +3684,8 @@ extern Lisp_Object Qand_rest; | |||
| 3677 | extern Lisp_Object Vautoload_queue; | 3684 | extern Lisp_Object Vautoload_queue; |
| 3678 | extern Lisp_Object Vsignaling_function; | 3685 | extern Lisp_Object Vsignaling_function; |
| 3679 | extern Lisp_Object inhibit_lisp_code; | 3686 | extern Lisp_Object inhibit_lisp_code; |
| 3680 | #if BYTE_MARK_STACK | ||
| 3681 | extern struct catchtag *catchlist; | ||
| 3682 | extern struct handler *handlerlist; | 3687 | extern struct handler *handlerlist; |
| 3683 | #endif | 3688 | |
| 3684 | /* To run a normal hook, use the appropriate function from the list below. | 3689 | /* To run a normal hook, use the appropriate function from the list below. |
| 3685 | The calling convention: | 3690 | The calling convention: |
| 3686 | 3691 | ||