1 /*
2  * vmP.h - ScmVM private API
3  *
4  *   Copyright (c) 2017-2020  Shiro Kawai  <shiro@acm.org>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   3. Neither the name of the authors nor the names of its contributors
18  *      may be used to endorse or promote products derived from this
19  *      software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef GAUCHE_PRIV_VMP_H
35 #define GAUCHE_PRIV_VMP_H
36 
37 #include "gauche/vm.h"
38 
39 SCM_DECL_BEGIN
40 
41 /*
42  * Escape point
43  *
44  *  EscapePoint (EP) structure keeps certain point of continuation chain
45  *  where control can be transferred.   This structure is used for
46  *  saved continuations, as well as error handlers.
47  *
48  *  Normally EPs forms a single list, linked by the prev pointer.
49  *  vm->escapePoint points a 'current' EP, whose ehandler is the current
50  *  error handler.
51  *
52  *  However, this simple structure does not work in all cases.
53  *  When an error is signalled, we pop EP before executing the error
54  *  handler so that an error raised within the error handler will be
55  *  handled by the handler of outer EP.
56  *
57  *    Suppose the current EP is EP0.
58  *
59  *    (with-error-handler    ;; <- (1)this installs EP1. EP1->cont captures
60  *                           ;;        one-shot continuation of this expr.
61  *       (lambda (e) ...)    ;; <- (3)this is executed while EP0 is current
62  *      (lambda () ...)      ;; <- (2)this is executed while EP1 is current
63  *
64  *  If the error handler returns, we pass its result to the continuation of
65  *  with-error-handler, which is kept in EP1->cont.  The problem arises
66  *  if a stack overflow occurs within the error handler, continuation frames
67  *  in the stack are relocated to the heap, but EP1->cont isn't updated
68  *  since it is out of vm->escapePoint chain.
69  *
70  *  'Floating' pointer is used to catch such case.  When an EP is popped
71  *  before an error handler is ivoked, EP0's floating pointer is set to
72  *  point EP1.  When a new EP is pushed, it inherits the previous EP's
73  *  floating pointer.  With this scheme, active floating EPs are always
74  *  reachable from vm->esapePoint->floating chain.  (NB: the chain length
75  *  can be more than 1, if with-error-handler is used within an error handler
76  *  and an error is signalled in its body.
77  */
78 typedef struct ScmEscapePointRec {
79     struct ScmEscapePointRec *prev;
80     struct ScmEscapePointRec *floating;
81     ScmObj ehandler;            /* handler closure */
82     ScmContFrame *cont;         /* saved continuation */
83     ScmObj handlers;            /* saved dynamic handler chain */
84     ScmCStack *cstack;          /* vm->cstack when escape point is created.
85                                    this will be used to rewind cstack.
86                                    this is NULL for partial continuations,
87                                    for they can be executed on anywhere
88                                    w.r.t. cstack. */
89     ScmObj xhandler;            /* saved exception handler */
90     ScmObj resetChain;          /* for reset/shift */
91     ScmObj partHandlers;        /* for reset/shift */
92     int errorReporting;         /* state of SCM_VM_ERROR_REPORTING flag
93                                    when this ep is captured.  The flag status
94                                    should be restored when the control
95                                    transferred to this escape point. */
96     int rewindBefore;           /* EXPERIMENTAL: if TRUE, dynamic handlers
97                                    are rewound after an exception is raised
98                                    and before the exception handler is called.
99                                    If FALSE, the exception handler is called
100                                    first, then the dynamic handlers are
101                                    rewound.   SRFI-18 model and legacy
102                                    with-error-handler uses the latter model,
103                                    but SRFI-34's guard needs the former model.
104                                 */
105     int reraised;               /* EXPERIMENTAL: if exception is reraised,
106                                    this flag is set to TRUE and the exception
107                                    handler can return to the caller. */
108 } ScmEscapePoint;
109 
110 /* Link management */
111 #define SCM_VM_FLOATING_EP(vm) \
112     ((vm)->escapePoint? (vm)->escapePoint->floating : vm->escapePointFloating)
113 #define SCM_VM_FLOATING_EP_SET(vm, ep)          \
114     do {                                        \
115         if ((vm)->escapePoint) {                \
116             (vm)->escapePoint->floating = (ep); \
117         } else {                                \
118             (vm)->escapePointFloating = (ep);   \
119         }                                       \
120     } while (0)
121 
122 /* Escape types */
123 #define SCM_VM_ESCAPE_NONE   0
124 #define SCM_VM_ESCAPE_ERROR  1
125 #define SCM_VM_ESCAPE_CONT   2
126 #define SCM_VM_ESCAPE_EXIT   3
127 
128 /*
129  * Call Trace
130  */
131 
132 typedef struct ScmCallTraceEntryRec {
133     ScmCompiledCode *base;
134     SCM_PCTYPE pc;
135 } ScmCallTraceEntry;
136 
137 struct ScmCallTraceRec {
138     u_long size;                  /* size of the array, must be 2^n */
139     u_long top;                   /* index to the next entry */
140     ScmCallTraceEntry entries[1]; /* variable length */
141 };
142 
143 ScmCallTrace *Scm__MakeCallTraceQueue(u_long size);
144 
145 
146 /* For BF and BT instructions, we check for #<undef>.
147    This macro assumes to the local variable VM holding ScmVM*.
148  */
149 #define SCM_CHECKED_FALSEP(obj) \
150     (SCM_FALSEP(obj) || (SCM_UNDEFINEDP(obj)&&Scm_VMUndefinedBool(vm)))
151 SCM_EXTERN int Scm_VMUndefinedBool(ScmVM*); /* in boolean.c */
152 
153 
154 SCM_DECL_END
155 
156 #endif /*GAUCHE_PRIV_VMP_H*/
157