2010-04-03 05:58:14 +01:00
|
|
|
/************************************************************************
|
|
|
|
** **
|
|
|
|
** The YapTab/YapOr/OPTYap systems **
|
|
|
|
** **
|
|
|
|
** YapTab extends the Yap Prolog engine to support sequential tabling **
|
|
|
|
** YapOr extends the Yap Prolog engine to support or-parallelism **
|
|
|
|
** OPTYap extends the Yap Prolog engine to support or-parallel tabling **
|
|
|
|
** **
|
|
|
|
** **
|
|
|
|
** Yap Prolog was developed at University of Porto, Portugal **
|
|
|
|
** **
|
|
|
|
************************************************************************/
|
|
|
|
|
2010-04-16 02:08:06 +01:00
|
|
|
/************************************************************************
|
|
|
|
** Table Space Data Structures **
|
|
|
|
************************************************************************/
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
** table_entry **
|
|
|
|
**************************/
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
typedef struct table_entry {
|
2009-12-18 02:19:49 +00:00
|
|
|
#if defined(YAPOR) || defined(THREADS)
|
2001-04-09 20:54:03 +01:00
|
|
|
lockvar lock;
|
2010-04-16 02:08:06 +01:00
|
|
|
#endif /* YAPOR || THREADS */
|
2005-07-06 20:34:12 +01:00
|
|
|
struct pred_entry *pred_entry;
|
2009-06-17 17:14:16 +01:00
|
|
|
Atom pred_atom;
|
2005-07-06 20:34:12 +01:00
|
|
|
int pred_arity;
|
2010-04-16 02:08:06 +01:00
|
|
|
short pred_flags;
|
|
|
|
short execution_mode; /* combines yap_flags with pred_flags */
|
2011-10-22 16:49:13 +01:00
|
|
|
#ifdef MODE_DIRECTED_TABLING
|
|
|
|
int* mode_directed_array;
|
|
|
|
#endif /*MODE_DIRECTED_TABLING*/
|
2011-11-09 11:00:31 +00:00
|
|
|
struct subgoal_trie_node *subgoal_trie;
|
|
|
|
struct subgoal_trie_hash *hash_chain;
|
2001-04-09 20:54:03 +01:00
|
|
|
struct table_entry *next;
|
|
|
|
} *tab_ent_ptr;
|
|
|
|
|
2011-11-09 11:00:31 +00:00
|
|
|
#define TabEnt_lock(X) ((X)->lock)
|
|
|
|
#define TabEnt_pe(X) ((X)->pred_entry)
|
|
|
|
#define TabEnt_atom(X) ((X)->pred_atom)
|
|
|
|
#define TabEnt_arity(X) ((X)->pred_arity)
|
|
|
|
#define TabEnt_flags(X) ((X)->pred_flags)
|
|
|
|
#define TabEnt_mode(X) ((X)->execution_mode)
|
|
|
|
#define TabEnt_mode_directed(X) ((X)->mode_directed_array)
|
|
|
|
#define TabEnt_subgoal_trie(X) ((X)->subgoal_trie)
|
|
|
|
#define TabEnt_hash_chain(X) ((X)->hash_chain)
|
|
|
|
#define TabEnt_next(X) ((X)->next)
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2010-04-16 02:08:06 +01:00
|
|
|
/***********************************************************************
|
|
|
|
** global_trie_node, subgoal_trie_node and answer_trie_node **
|
|
|
|
***********************************************************************/
|
2009-09-27 02:31:31 +01:00
|
|
|
|
2001-04-09 20:54:03 +01:00
|
|
|
typedef struct subgoal_trie_node {
|
|
|
|
Term entry;
|
|
|
|
struct subgoal_trie_node *parent;
|
2005-04-07 18:56:58 +01:00
|
|
|
struct subgoal_trie_node *child;
|
2001-04-09 20:54:03 +01:00
|
|
|
struct subgoal_trie_node *next;
|
2010-04-19 02:34:08 +01:00
|
|
|
#ifdef TABLE_LOCK_AT_NODE_LEVEL
|
|
|
|
lockvar lock;
|
|
|
|
#endif /* TABLE_LOCK_AT_NODE_LEVEL */
|
2001-04-09 20:54:03 +01:00
|
|
|
} *sg_node_ptr;
|
|
|
|
|
|
|
|
typedef struct answer_trie_node {
|
|
|
|
OPCODE trie_instruction; /* u.opc */
|
|
|
|
#ifdef YAPOR
|
2008-09-05 05:22:19 +01:00
|
|
|
int or_arg; /* u.Otapl.or_arg */
|
2001-04-09 20:54:03 +01:00
|
|
|
#endif /* YAPOR */
|
|
|
|
Term entry;
|
|
|
|
struct answer_trie_node *parent;
|
2005-04-07 18:56:58 +01:00
|
|
|
struct answer_trie_node *child;
|
2001-04-09 20:54:03 +01:00
|
|
|
struct answer_trie_node *next;
|
2010-04-19 02:34:08 +01:00
|
|
|
#ifdef TABLE_LOCK_AT_NODE_LEVEL
|
|
|
|
lockvar lock;
|
|
|
|
#endif /* TABLE_LOCK_AT_NODE_LEVEL */
|
2001-04-09 20:54:03 +01:00
|
|
|
} *ans_node_ptr;
|
|
|
|
|
2010-04-23 04:22:10 +01:00
|
|
|
typedef struct global_trie_node {
|
|
|
|
Term entry;
|
|
|
|
struct global_trie_node *parent;
|
|
|
|
struct global_trie_node *child;
|
|
|
|
struct global_trie_node *next;
|
|
|
|
#ifdef TABLE_LOCK_AT_NODE_LEVEL
|
|
|
|
lockvar lock;
|
|
|
|
#endif /* TABLE_LOCK_AT_NODE_LEVEL */
|
|
|
|
} *gt_node_ptr;
|
|
|
|
|
|
|
|
#define TrNode_instr(X) ((X)->trie_instruction)
|
|
|
|
#define TrNode_or_arg(X) ((X)->or_arg)
|
|
|
|
#define TrNode_entry(X) ((X)->entry)
|
|
|
|
#define TrNode_parent(X) ((X)->parent)
|
|
|
|
#define TrNode_child(X) ((X)->child)
|
|
|
|
#define TrNode_sg_fr(X) ((X)->child)
|
|
|
|
#define TrNode_next(X) ((X)->next)
|
|
|
|
#define TrNode_lock(X) ((X)->lock)
|
2011-11-09 11:00:31 +00:00
|
|
|
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
|
2010-04-16 02:08:06 +01:00
|
|
|
/***********************************************************************
|
|
|
|
** global_trie_hash, subgoal_trie_hash and answer_trie_hash **
|
|
|
|
***********************************************************************/
|
2009-09-27 02:31:31 +01:00
|
|
|
|
|
|
|
typedef struct subgoal_trie_hash {
|
2001-04-09 20:54:03 +01:00
|
|
|
/* the first field is used for compatibility **
|
|
|
|
** with the subgoal_trie_node data structure */
|
|
|
|
Term mark;
|
|
|
|
int number_of_buckets;
|
|
|
|
struct subgoal_trie_node **buckets;
|
|
|
|
int number_of_nodes;
|
2009-09-27 02:31:31 +01:00
|
|
|
struct subgoal_trie_hash *next;
|
2001-04-09 20:54:03 +01:00
|
|
|
} *sg_hash_ptr;
|
|
|
|
|
2009-09-27 02:31:31 +01:00
|
|
|
typedef struct answer_trie_hash {
|
2001-04-09 20:54:03 +01:00
|
|
|
/* the first field is used for compatibility **
|
|
|
|
** with the answer_trie_node data structure */
|
|
|
|
OPCODE mark;
|
|
|
|
int number_of_buckets;
|
|
|
|
struct answer_trie_node **buckets;
|
|
|
|
int number_of_nodes;
|
2011-10-22 16:49:13 +01:00
|
|
|
#ifdef MODE_DIRECTED_TABLING
|
|
|
|
struct answer_trie_hash *previous;
|
|
|
|
#endif /*MODE_DIRECTED_TABLING*/
|
2011-11-09 11:00:31 +00:00
|
|
|
struct answer_trie_hash *next;
|
2001-04-09 20:54:03 +01:00
|
|
|
} *ans_hash_ptr;
|
|
|
|
|
2010-04-23 04:22:10 +01:00
|
|
|
typedef struct global_trie_hash {
|
|
|
|
/* the first field is used for compatibility **
|
|
|
|
** with the global_trie_node data structure */
|
|
|
|
Term mark;
|
|
|
|
int number_of_buckets;
|
|
|
|
struct global_trie_node **buckets;
|
|
|
|
int number_of_nodes;
|
2011-04-28 09:48:42 +01:00
|
|
|
#ifdef USE_PAGES_MALLOC
|
2011-04-18 14:59:17 +01:00
|
|
|
struct global_trie_hash *next;
|
2011-04-28 09:48:42 +01:00
|
|
|
#endif /* USE_PAGES_MALLOC */
|
2010-04-23 04:22:10 +01:00
|
|
|
} *gt_hash_ptr;
|
|
|
|
|
|
|
|
#define Hash_mark(X) ((X)->mark)
|
|
|
|
#define Hash_num_buckets(X) ((X)->number_of_buckets)
|
|
|
|
#define Hash_seed(X) ((X)->number_of_buckets - 1)
|
|
|
|
#define Hash_buckets(X) ((X)->buckets)
|
|
|
|
#define Hash_bucket(X,N) ((X)->buckets + N)
|
|
|
|
#define Hash_num_nodes(X) ((X)->number_of_nodes)
|
2011-11-09 11:00:31 +00:00
|
|
|
#define Hash_previous(X) ((X)->previous)
|
2010-04-23 04:22:10 +01:00
|
|
|
#define Hash_next(X) ((X)->next)
|
2011-11-09 11:00:31 +00:00
|
|
|
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
|
2010-04-16 02:08:06 +01:00
|
|
|
/************************************************************************
|
|
|
|
** Execution Data Structures **
|
|
|
|
************************************************************************/
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
** choice points **
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
struct generator_choicept {
|
|
|
|
struct choicept cp;
|
|
|
|
struct dependency_frame *cp_dep_fr; /* always NULL if batched scheduling */
|
|
|
|
struct subgoal_frame *cp_sg_fr;
|
|
|
|
#ifdef LOW_LEVEL_TRACER
|
|
|
|
struct pred_entry *cp_pred_entry;
|
|
|
|
#endif /* LOW_LEVEL_TRACER */
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef DETERMINISTIC_TABLING
|
|
|
|
struct deterministic_generator_choicept {
|
|
|
|
struct deterministic_choicept cp;
|
|
|
|
struct subgoal_frame *cp_sg_fr;
|
|
|
|
#ifdef LOW_LEVEL_TRACER
|
|
|
|
struct pred_entry *cp_pred_entry;
|
|
|
|
#endif /* LOW_LEVEL_TRACER */
|
|
|
|
};
|
|
|
|
#endif /* DETERMINISTIC_TABLING */
|
|
|
|
|
|
|
|
struct consumer_choicept {
|
|
|
|
struct choicept cp;
|
|
|
|
struct dependency_frame *cp_dep_fr;
|
|
|
|
#ifdef LOW_LEVEL_TRACER
|
|
|
|
struct pred_entry *cp_pred_entry;
|
|
|
|
#endif /* LOW_LEVEL_TRACER */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct loader_choicept {
|
|
|
|
struct choicept cp;
|
|
|
|
struct answer_trie_node *cp_last_answer;
|
|
|
|
#ifdef LOW_LEVEL_TRACER
|
|
|
|
struct pred_entry *cp_pred_entry;
|
|
|
|
#endif /* LOW_LEVEL_TRACER */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
** subgoal_frame **
|
|
|
|
****************************/
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
typedef struct subgoal_frame {
|
2009-12-18 02:19:49 +00:00
|
|
|
#if defined(YAPOR) || defined(THREADS)
|
2001-04-09 20:54:03 +01:00
|
|
|
lockvar lock;
|
2010-04-19 02:34:08 +01:00
|
|
|
#endif /* YAPOR || THREADS */
|
2009-12-18 02:19:49 +00:00
|
|
|
#ifdef YAPOR
|
2001-04-09 20:54:03 +01:00
|
|
|
int generator_worker;
|
|
|
|
struct or_frame *top_or_frame_on_generator_branch;
|
|
|
|
#endif /* YAPOR */
|
2005-08-01 16:40:39 +01:00
|
|
|
yamop *code_of_subgoal;
|
2010-04-16 02:08:06 +01:00
|
|
|
enum { /* do not change order !!! */
|
2005-08-04 16:45:56 +01:00
|
|
|
incomplete = 0, /* INCOMPLETE_TABLING */
|
|
|
|
ready = 1,
|
|
|
|
evaluating = 2,
|
|
|
|
complete = 3,
|
|
|
|
complete_in_use = 4, /* LIMIT_TABLING */
|
|
|
|
compiled = 5,
|
|
|
|
compiled_in_use = 6 /* LIMIT_TABLING */
|
2010-04-16 02:08:06 +01:00
|
|
|
} state_flag;
|
2005-08-01 16:40:39 +01:00
|
|
|
choiceptr generator_choice_point;
|
2009-09-27 02:31:31 +01:00
|
|
|
struct answer_trie_hash *hash_chain;
|
2005-08-01 16:40:39 +01:00
|
|
|
struct answer_trie_node *answer_trie;
|
|
|
|
struct answer_trie_node *first_answer;
|
|
|
|
struct answer_trie_node *last_answer;
|
|
|
|
#ifdef INCOMPLETE_TABLING
|
|
|
|
struct answer_trie_node *try_answer;
|
|
|
|
#endif /* INCOMPLETE_TABLING */
|
2011-11-09 11:00:31 +00:00
|
|
|
#ifdef MODE_DIRECTED_TABLING
|
|
|
|
struct answer_trie_node *invalid_chain;
|
|
|
|
int* mode_directed_array;
|
|
|
|
#endif /*MODE_DIRECTED_TABLING*/
|
2005-08-04 16:45:56 +01:00
|
|
|
#ifdef LIMIT_TABLING
|
|
|
|
struct subgoal_frame *previous;
|
|
|
|
#endif /* LIMIT_TABLING */
|
2001-04-09 20:54:03 +01:00
|
|
|
struct subgoal_frame *next;
|
|
|
|
} *sg_fr_ptr;
|
|
|
|
|
|
|
|
#define SgFr_lock(X) ((X)->lock)
|
|
|
|
#define SgFr_gen_worker(X) ((X)->generator_worker)
|
|
|
|
#define SgFr_gen_top_or_fr(X) ((X)->top_or_frame_on_generator_branch)
|
2005-08-01 16:40:39 +01:00
|
|
|
#define SgFr_code(X) ((X)->code_of_subgoal)
|
2008-09-05 05:22:19 +01:00
|
|
|
#define SgFr_tab_ent(X) (((X)->code_of_subgoal)->u.Otapl.te)
|
|
|
|
#define SgFr_arity(X) (((X)->code_of_subgoal)->u.Otapl.s)
|
2005-08-01 16:40:39 +01:00
|
|
|
#define SgFr_state(X) ((X)->state_flag)
|
2001-04-09 20:54:03 +01:00
|
|
|
#define SgFr_gen_cp(X) ((X)->generator_choice_point)
|
2005-08-01 16:40:39 +01:00
|
|
|
#define SgFr_hash_chain(X) ((X)->hash_chain)
|
2001-04-09 20:54:03 +01:00
|
|
|
#define SgFr_answer_trie(X) ((X)->answer_trie)
|
|
|
|
#define SgFr_first_answer(X) ((X)->first_answer)
|
|
|
|
#define SgFr_last_answer(X) ((X)->last_answer)
|
2005-08-01 16:40:39 +01:00
|
|
|
#define SgFr_try_answer(X) ((X)->try_answer)
|
2011-11-09 11:00:31 +00:00
|
|
|
#define SgFr_invalid_chain(X) ((X)->invalid_chain)
|
|
|
|
#define SgFr_mode_directed(X) ((X)->mode_directed_array)
|
2005-08-04 16:45:56 +01:00
|
|
|
#define SgFr_previous(X) ((X)->previous)
|
2001-04-09 20:54:03 +01:00
|
|
|
#define SgFr_next(X) ((X)->next)
|
2011-11-09 11:00:31 +00:00
|
|
|
|
2010-04-03 05:58:14 +01:00
|
|
|
/**************************************************************************************************
|
|
|
|
|
|
|
|
SgFr_lock: spin-lock to modify the frame fields.
|
|
|
|
SgFr_gen_worker: the id of the worker that had allocated the frame.
|
|
|
|
SgFr_gen_top_or_fr: a pointer to the top or-frame in the generator choice point branch.
|
|
|
|
When the generator choice point is shared the pointer is updated
|
|
|
|
to its or-frame. It is used to find the direct dependency node for
|
|
|
|
consumer nodes in other workers branches.
|
|
|
|
SgFr_code initial instruction of the subgoal's compiled code.
|
|
|
|
SgFr_tab_ent a pointer to the correspondent table entry.
|
|
|
|
SgFr_arity the arity of the subgoal.
|
|
|
|
SgFr_state: a flag that indicates the subgoal state.
|
|
|
|
SgFr_gen_cp: a pointer to the correspondent generator choice point.
|
|
|
|
SgFr_hash_chain: a pointer to the first answer_trie_hash struct for the subgoal in hand.
|
|
|
|
SgFr_answer_trie: a pointer to the top answer trie node.
|
|
|
|
It is used to check for/insert new answers.
|
|
|
|
SgFr_first_answer: a pointer to the bottom answer trie node of the first available answer.
|
|
|
|
SgFr_last_answer: a pointer to the bottom answer trie node of the last available answer.
|
|
|
|
SgFr_try_answer: a pointer to the bottom answer trie node of the last tried answer.
|
|
|
|
It is used when a subgoal was not completed during the previous evaluation.
|
|
|
|
Not completed subgoals start by trying the answers already found.
|
2011-11-09 11:00:31 +00:00
|
|
|
SgFr_invalid_chain: a pointer to the first invalid leaf node when using mode directed tabling.
|
|
|
|
SgFr_mode_directed: a pointer to the mode directed array.
|
2010-04-03 05:58:14 +01:00
|
|
|
SgFr_previous: a pointer to the previous subgoal frame on the chain.
|
|
|
|
SgFr_next: a pointer to the next subgoal frame on the chain.
|
|
|
|
|
|
|
|
**************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-04-16 02:08:06 +01:00
|
|
|
/*******************************
|
|
|
|
** dependency_frame **
|
|
|
|
*******************************/
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
typedef struct dependency_frame {
|
2009-12-18 02:19:49 +00:00
|
|
|
#if defined(YAPOR) || defined(THREADS)
|
2001-04-09 20:54:03 +01:00
|
|
|
lockvar lock;
|
2010-04-16 02:08:06 +01:00
|
|
|
#endif /* YAPOR || THREADS */
|
2009-12-18 02:19:49 +00:00
|
|
|
#ifdef YAPOR
|
2001-04-09 20:54:03 +01:00
|
|
|
int leader_dependency_is_on_stack;
|
|
|
|
struct or_frame *top_or_frame;
|
|
|
|
#ifdef TIMESTAMP_CHECK
|
|
|
|
long timestamp;
|
|
|
|
#endif /* TIMESTAMP_CHECK */
|
|
|
|
#endif /* YAPOR */
|
|
|
|
choiceptr backchain_choice_point;
|
|
|
|
choiceptr leader_choice_point;
|
|
|
|
choiceptr consumer_choice_point;
|
|
|
|
struct answer_trie_node *last_consumed_answer;
|
|
|
|
struct dependency_frame *next;
|
|
|
|
} *dep_fr_ptr;
|
|
|
|
|
|
|
|
#define DepFr_lock(X) ((X)->lock)
|
|
|
|
#define DepFr_leader_dep_is_on_stack(X) ((X)->leader_dependency_is_on_stack)
|
|
|
|
#define DepFr_top_or_fr(X) ((X)->top_or_frame)
|
|
|
|
#define DepFr_timestamp(X) ((X)->timestamp)
|
|
|
|
#define DepFr_backchain_cp(X) ((X)->backchain_choice_point)
|
|
|
|
#define DepFr_leader_cp(X) ((X)->leader_choice_point)
|
|
|
|
#define DepFr_cons_cp(X) ((X)->consumer_choice_point)
|
2005-04-07 18:56:58 +01:00
|
|
|
#define DepFr_last_answer(X) ((X)->last_consumed_answer)
|
2001-04-09 20:54:03 +01:00
|
|
|
#define DepFr_next(X) ((X)->next)
|
|
|
|
|
2010-04-03 05:58:14 +01:00
|
|
|
/*******************************************************************************************************
|
|
|
|
|
|
|
|
DepFr_lock: lock variable to modify the frame fields.
|
|
|
|
DepFr_leader_dep_is_on_stack: the generator choice point for the correspondent consumer choice point
|
|
|
|
is on the worker's stack (FALSE/TRUE).
|
|
|
|
DepFr_top_or_fr: a pointer to the top or-frame in the consumer choice point branch.
|
|
|
|
When the consumer choice point is shared the pointer is updated to
|
|
|
|
its or-frame. It is used to update the LOCAL_top_or_fr when a worker
|
|
|
|
backtracks through answers.
|
|
|
|
DepFr_timestamp: a timestamp used to optimize the search for suspension frames to be
|
|
|
|
resumed.
|
|
|
|
DepFr_backchain_cp: a pointer to the nearest choice point with untried alternatives.
|
|
|
|
It is used to efficiently return (backtrack) to the leader node where
|
|
|
|
we perform the last backtracking through answers operation.
|
|
|
|
DepFr_leader_cp: a pointer to the leader choice point.
|
|
|
|
DepFr_cons_cp: a pointer to the correspondent consumer choice point.
|
|
|
|
DepFr_last_answer: a pointer to the last consumed answer.
|
|
|
|
DepFr_next: a pointer to the next dependency frame on the chain.
|
|
|
|
|
|
|
|
*******************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-04-16 02:08:06 +01:00
|
|
|
/*******************************
|
|
|
|
** suspension_frame **
|
|
|
|
*******************************/
|
2001-04-09 20:54:03 +01:00
|
|
|
|
|
|
|
#ifdef YAPOR
|
|
|
|
typedef struct suspension_frame {
|
|
|
|
struct or_frame *top_or_frame_on_stack;
|
|
|
|
struct dependency_frame *top_dependency_frame;
|
|
|
|
struct subgoal_frame *top_subgoal_frame;
|
|
|
|
struct suspended_block {
|
|
|
|
void *resume_register;
|
|
|
|
void *block_start;
|
|
|
|
long block_size;
|
|
|
|
} global_block, local_block, trail_block;
|
|
|
|
struct suspension_frame *next;
|
|
|
|
} *susp_fr_ptr;
|
|
|
|
#endif /* YAPOR */
|
|
|
|
|
|
|
|
#define SuspFr_top_or_fr_on_stack(X) ((X)->top_or_frame_on_stack)
|
|
|
|
#define SuspFr_top_dep_fr(X) ((X)->top_dependency_frame)
|
|
|
|
#define SuspFr_top_sg_fr(X) ((X)->top_subgoal_frame)
|
|
|
|
#define SuspFr_global_reg(X) ((X)->global_block.resume_register)
|
|
|
|
#define SuspFr_global_start(X) ((X)->global_block.block_start)
|
|
|
|
#define SuspFr_global_size(X) ((X)->global_block.block_size)
|
|
|
|
#define SuspFr_local_reg(X) ((X)->local_block.resume_register)
|
|
|
|
#define SuspFr_local_start(X) ((X)->local_block.block_start)
|
|
|
|
#define SuspFr_local_size(X) ((X)->local_block.block_size)
|
|
|
|
#define SuspFr_trail_reg(X) ((X)->trail_block.resume_register)
|
|
|
|
#define SuspFr_trail_start(X) ((X)->trail_block.block_start)
|
|
|
|
#define SuspFr_trail_size(X) ((X)->trail_block.block_size)
|
|
|
|
#define SuspFr_next(X) ((X)->next)
|