diff options
Diffstat (limited to 'libguile/dynstack.h')
-rw-r--r-- | libguile/dynstack.h | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/libguile/dynstack.h b/libguile/dynstack.h new file mode 100644 index 000000000..33389cad7 --- /dev/null +++ b/libguile/dynstack.h @@ -0,0 +1,206 @@ +/* classes: h_files */ + +#ifndef SCM_DYNSTACK_H +#define SCM_DYNSTACK_H + +/* Copyright (C) 2012 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + + +#include "libguile/__scm.h" +#include "libguile/control.h" + + + +typedef struct +{ + scm_t_bits *base; + scm_t_bits *top; + scm_t_bits *limit; +} scm_t_dynstack; + + + +/* Items on the dynstack are preceded by two-word headers, giving the + offset of the preceding item (or 0 if there is none) and the type, + flags, and length of the following dynstack entry, in words. In + addition, there is a "null header" at the top of the stack, + indicating the length of the previous item, but with a tag of zero. + + For example, consider an empty dynstack, with a capacity of 6 words: + + +----------+----------+ + + |prev=0 |tag=0 | | + +----------+----------+ + + ^base ^top limit^ + + Now we evaluate (dynamic-wind enter thunk leave). That will result + in a dynstack of: + + / the len=2 words \ + +----------+----------+----------+----------+----------+----------+ + |prev=0 |tag:len=2 |enter |leave |prev=4 |tag=0 | + +----------+----------+----------+----------+----------+----------+ + ^base top,limit^ + + The tag is a combination of the type of the dynstack item, some flags + associated with the item, and the length of the item. See + SCM_MAKE_DYNSTACK_TAG below for the details. + + This arrangement makes it possible to have variable-length dynstack + items, and yet be able to traverse them forwards or backwards. */ + +#define SCM_DYNSTACK_HEADER_LEN 2 + +#define SCM_DYNSTACK_PREV_OFFSET(top) ((top)[-2]) +#define SCM_DYNSTACK_SET_PREV_OFFSET(top, offset) (top)[-2] = (offset) + +#define SCM_DYNSTACK_TAG(top) ((top)[-1]) +#define SCM_DYNSTACK_SET_TAG(top, tag) (top)[-1] = (tag) + +typedef enum { + SCM_DYNSTACK_TYPE_NONE = 0, + SCM_DYNSTACK_TYPE_FRAME, + SCM_DYNSTACK_TYPE_UNWINDER, + SCM_DYNSTACK_TYPE_REWINDER, + SCM_DYNSTACK_TYPE_WITH_FLUIDS, + SCM_DYNSTACK_TYPE_PROMPT, + SCM_DYNSTACK_TYPE_DYNWIND, +} scm_t_dynstack_item_type; + +#define SCM_DYNSTACK_TAG_TYPE_MASK 0xf +#define SCM_DYNSTACK_TAG_FLAGS_MASK 0xf0 +#define SCM_DYNSTACK_TAG_FLAGS_SHIFT 4 +#define SCM_DYNSTACK_TAG_LEN_SHIFT 8 + +#define SCM_MAKE_DYNSTACK_TAG(type, flags, len) \ + ((type) | (flags) | ((len) << SCM_DYNSTACK_TAG_LEN_SHIFT)) + +#define SCM_DYNSTACK_TAG_TYPE(tag) \ + ((tag) & SCM_DYNSTACK_TAG_TYPE_MASK) +#define SCM_DYNSTACK_TAG_FLAGS(tag) \ + ((tag) & SCM_DYNSTACK_TAG_FLAGS_MASK) +#define SCM_DYNSTACK_TAG_LEN(tag) \ + ((tag) >> SCM_DYNSTACK_TAG_LEN_SHIFT) + +#define SCM_DYNSTACK_PREV(top) \ + (SCM_DYNSTACK_PREV_OFFSET (top) \ + ? ((top) - SCM_DYNSTACK_PREV_OFFSET (top)) : NULL) +#define SCM_DYNSTACK_NEXT(top) \ + (SCM_DYNSTACK_TAG (top) \ + ? ((top) + SCM_DYNSTACK_TAG_LEN (SCM_DYNSTACK_TAG (top)) \ + + SCM_DYNSTACK_HEADER_LEN) \ + : NULL) + +#define SCM_DYNSTACK_FIRST(dynstack) \ + ((dynstack)->base + SCM_DYNSTACK_HEADER_LEN) + +#define SCM_DYNSTACK_CAPACITY(dynstack) \ + ((dynstack)->limit - (dynstack)->base) +#define SCM_DYNSTACK_SPACE(dynstack) \ + ((dynstack)->limit - (dynstack)->top) +#define SCM_DYNSTACK_HEIGHT(dynstack) \ + ((dynstack)->top - (dynstack)->base) + +#define SCM_DYNSTACK_HAS_SPACE(dynstack, n) \ + (SCM_DYNSTACK_SPACE (dynstack) >= n + SCM_DYNSTACK_HEADER_LEN) + +typedef enum { + SCM_F_DYNSTACK_FRAME_REWINDABLE = (1 << SCM_DYNSTACK_TAG_FLAGS_SHIFT) +} scm_t_dynstack_frame_flags; + +typedef enum { + SCM_F_DYNSTACK_WINDER_EXPLICIT = (1 << SCM_DYNSTACK_TAG_FLAGS_SHIFT) +} scm_t_dynstack_winder_flags; + +typedef enum { + SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY = (1 << SCM_DYNSTACK_TAG_FLAGS_SHIFT) +} scm_t_dynstack_prompt_flags; + +typedef void (*scm_t_guard) (void *); + + + + +/* Pushing and popping entries on the dynamic stack. */ + +SCM_INTERNAL void scm_dynstack_push_frame (scm_t_dynstack *, + scm_t_dynstack_frame_flags); +SCM_INTERNAL void scm_dynstack_push_rewinder (scm_t_dynstack *, + scm_t_dynstack_winder_flags, + scm_t_guard, void *); +SCM_INTERNAL void scm_dynstack_push_unwinder (scm_t_dynstack *, + scm_t_dynstack_winder_flags, + scm_t_guard, void *); +SCM_INTERNAL void scm_dynstack_push_fluids (scm_t_dynstack *, + size_t, + SCM *fluids, + SCM *values, + SCM dynamic_state); +SCM_INTERNAL void scm_dynstack_push_prompt (scm_t_dynstack *, + scm_t_dynstack_prompt_flags, + SCM key, + scm_t_prompt_registers *); +SCM_INTERNAL void scm_dynstack_push_dynwind (scm_t_dynstack *, + SCM enter, SCM leave); + +SCM_INTERNAL void scm_dynstack_pop (scm_t_dynstack *); + + + + +/* Capturing, winding, and unwinding. */ + +SCM_INTERNAL scm_t_dynstack* scm_dynstack_capture_all (scm_t_dynstack *dynstack); +SCM_INTERNAL scm_t_dynstack* scm_dynstack_capture (scm_t_dynstack *dynstack, + scm_t_bits *item); + +SCM_INTERNAL void scm_dynstack_wind_1 (scm_t_dynstack *, scm_t_bits *); +SCM_INTERNAL scm_t_bits scm_dynstack_unwind_1 (scm_t_dynstack *); + +SCM_INTERNAL void scm_dynstack_wind (scm_t_dynstack *, scm_t_bits *); +SCM_INTERNAL void scm_dynstack_unwind (scm_t_dynstack *, scm_t_bits *); + +SCM_INTERNAL scm_t_bits* scm_dynstack_unwind_fork (scm_t_dynstack *, + scm_t_dynstack *); + +SCM_INTERNAL void scm_dynstack_unwind_frame (scm_t_dynstack *); +SCM_INTERNAL void scm_dynstack_unwind_fluids (scm_t_dynstack *dynstack, + SCM dynamic_state); + + + + +/* Miscellany. */ + +SCM_INTERNAL scm_t_bits* scm_dynstack_find_prompt (scm_t_dynstack *, SCM, + scm_t_prompt_registers **, + scm_t_dynstack_prompt_flags *); + +SCM_INTERNAL scm_t_prompt_registers* +scm_dynstack_relocate_prompt (scm_t_dynstack *, scm_t_ptrdiff, scm_t_uint64); + + +#endif /* SCM_DYNSTACK_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ |