140 lines
6.8 KiB
C
140 lines
6.8 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2012 Fidelity Information Services, Inc *
|
||
|
* *
|
||
|
* This source code contains the intellectual property *
|
||
|
* of its copyright holder(s), and is made available *
|
||
|
* under a license. If you do not know the terms of *
|
||
|
* the license, please stop and do not read further. *
|
||
|
* *
|
||
|
****************************************************************/
|
||
|
|
||
|
#ifndef GLVN_POOL_H_INCLUDED
|
||
|
#define GLVN_POOL_H_INCLUDED
|
||
|
|
||
|
#include "callg.h"
|
||
|
#include "compiler.h"
|
||
|
#include "lv_val.h"
|
||
|
|
||
|
/* Here we provide tools for saving identifying information of local or global variables. For local variables this includes
|
||
|
* the variable name itself, as well as copies of each subscript. For global variables we save each argument that needs to
|
||
|
* be later passed into op_gvname/op_gvnaked/op_gvextnam. Note that deferring the op_gvnaked call allows us to achieve
|
||
|
* correct naked indicator flow. For example, in the command SET @"^(subs)"=rhs, the ^() needs to be evaluated relative to
|
||
|
* the expression on the right hand side, and the right hand side needs to happen AFTER the subscripts have been evaluated.
|
||
|
* The structure involved - the "glvn pool" - consists of a stack of entries, each corresponding to a single glvn, and
|
||
|
* a parallel stack of mvals, each corresponding to some parent entry. Both stacks are expandable, doubling in size whenever
|
||
|
* they run out of space. The glvn pool entries can be popped in three different ways. For SET, it's convenient to save the
|
||
|
* glvn pool state, i.e. the top of the array of still-relevant entries. After completion of the set, the pool is restored to
|
||
|
* this state and younger entries popped. With FOR, it's more convenient defer popping until another FOR loop at the same
|
||
|
* nesting level starts. At that time the previously used FOR slot is recycled and everything younger than it is popped.
|
||
|
* Finally, when a non-indirect frame is unwound, all younger pool entries are popped.
|
||
|
*/
|
||
|
|
||
|
#define ANY_SLOT 0
|
||
|
#define FIRST_SAVED_ARG(SLOT) ((OC_SAVLVN == (SLOT)->sav_opcode) ? 1 : 0)
|
||
|
/* To avoid breaking gtmpcat, we retain the 'for_ctrl_stack' field of the frame_pointer struct instead of replacing it
|
||
|
* with a uint4 'glvn_indx' field. The macros manipulate this field. Also for the convenience of gtmpcat: we declare the
|
||
|
* glvn_pool and glvn_pool_entry structs in compiler.h instead of here. This is because gtmpcat does not know to include
|
||
|
* glvn_pool.h when going through gtm_threadgbl_defs.h.
|
||
|
* When gtmpcat is changed to accommodate a new name, these macros and the stack frame struct need to be changed,
|
||
|
* and the glvn_pool structs in compiler.h should probably be moved into this file.
|
||
|
*/
|
||
|
#define GLVN_INDX(FP) ((uint4)(UINTPTR_T)((FP)->for_ctrl_stack))
|
||
|
#define GLVN_POOL_EMPTY ((uint4)-1) /* this must be an "impossible" value for a real pool */
|
||
|
#define GLVN_POOL_SLOTS_AVAILABLE ((TREF(glvn_pool_ptr))->capacity - (TREF(glvn_pool_ptr))->top)
|
||
|
#define GLVN_POOL_MVALS_AVAILABLE ((TREF(glvn_pool_ptr))->mval_capacity - (TREF(glvn_pool_ptr))->mval_top)
|
||
|
#define INIT_GLVN_POOL_CAPACITY 8
|
||
|
#define INIT_GLVN_POOL_MVAL_CAPACITY 64
|
||
|
#define GLVN_POOL_UNTOUCHED 0
|
||
|
#define MAX_EXPECTED_CAPACITY 2048
|
||
|
#define MAX_EXPECTED_MVAL_CAPACITY 2048
|
||
|
#define SLOT_NEEDS_REWIND(INDX) (((TREF(glvn_pool_ptr))->top <= (INDX)) && (GLVN_POOL_EMPTY != (INDX)))
|
||
|
#define SLOT_OPCODE(INDX) ((TREF(glvn_pool_ptr))->slot[INDX].sav_opcode)
|
||
|
|
||
|
#define SET_GLVN_INDX(FP, VALUE) \
|
||
|
{ \
|
||
|
(FP)->for_ctrl_stack = (unsigned char *)(UINTPTR_T)(VALUE); \
|
||
|
}
|
||
|
|
||
|
#define GLVN_POOL_EXPAND_IF_NEEDED \
|
||
|
{ \
|
||
|
if (!TREF(glvn_pool_ptr)) \
|
||
|
glvn_pool_init(); \
|
||
|
else if (!GLVN_POOL_SLOTS_AVAILABLE) \
|
||
|
glvn_pool_expand_slots(); \
|
||
|
}
|
||
|
|
||
|
#define ENSURE_GLVN_POOL_SPACE(SPC) \
|
||
|
{ \
|
||
|
if (GLVN_POOL_MVALS_AVAILABLE < (uint4)(SPC)) \
|
||
|
{ \
|
||
|
glvn_pool_expand_mvals(); \
|
||
|
assert(GLVN_POOL_MVALS_AVAILABLE >= (uint4)(SPC)); \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
#define GET_GLVN_POOL_STATE(SLOT, M) \
|
||
|
{ /* Find current available SLOT and mval. */ \
|
||
|
uint4 INDX, MVAL_INDX; \
|
||
|
\
|
||
|
INDX = (TREF(glvn_pool_ptr))->share_slot; \
|
||
|
SLOT = &(TREF(glvn_pool_ptr))->slot[INDX]; \
|
||
|
MVAL_INDX = SLOT->mval_top; \
|
||
|
M = &(TREF(glvn_pool_ptr))->mval_stack[MVAL_INDX]; \
|
||
|
}
|
||
|
|
||
|
#define DRAIN_GLVN_POOL_IF_NEEDED \
|
||
|
{ \
|
||
|
int I; \
|
||
|
uint4 INDX, FINDX; \
|
||
|
glvn_pool_entry *SLOT; \
|
||
|
\
|
||
|
if ((GLVN_POOL_UNTOUCHED != GLVN_INDX(frame_pointer)) && !(frame_pointer->flags & SFF_INDCE)) \
|
||
|
{ /* Someone used an ugly FOR control variable or did an indirect set. */ \
|
||
|
INDX = (GLVN_POOL_EMPTY != GLVN_INDX(frame_pointer)) ? GLVN_INDX(frame_pointer) : 0; \
|
||
|
op_glvnpop(INDX); \
|
||
|
for (I = 1; I <= MAX_FOR_STACK; I++) \
|
||
|
{ /* rewind the for_slot array */ \
|
||
|
FINDX = (TREF(glvn_pool_ptr))->for_slot[I]; \
|
||
|
if (SLOT_NEEDS_REWIND(FINDX)) \
|
||
|
{ /* reset to precursor */ \
|
||
|
SLOT = &(TREF(glvn_pool_ptr))->slot[FINDX]; \
|
||
|
assert(!SLOT_NEEDS_REWIND(SLOT->precursor)); \
|
||
|
(TREF(glvn_pool_ptr))->for_slot[I] = SLOT->precursor; \
|
||
|
} else /* no higher FOR levels were used by current frame */ \
|
||
|
break; \
|
||
|
} \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
#define INSERT_INDSAVGLVN(CTRL, V, RECYCLE, DO_REF) \
|
||
|
{ \
|
||
|
triple *PUSH, *SAV, *PAR; \
|
||
|
\
|
||
|
PUSH = newtriple(OC_GLVNSLOT); \
|
||
|
PUSH->operand[0] = put_ilit((mint)(RECYCLE)); \
|
||
|
CTRL = put_tref(PUSH); \
|
||
|
SAV = newtriple(OC_INDSAVGLVN); \
|
||
|
SAV->operand[0] = V; \
|
||
|
PAR = newtriple(OC_PARAMETER); \
|
||
|
SAV->operand[1] = put_tref(PAR); \
|
||
|
PAR->operand[0] = CTRL; \
|
||
|
PAR->operand[1] = put_ilit((mint)(DO_REF)); /* flag to suppress global reference here */ \
|
||
|
}
|
||
|
|
||
|
void glvn_pool_init(void); /* invoked via GLVN_POOL_EXPAND_IF_NEEDED macro */
|
||
|
void glvn_pool_expand_slots(void); /* invoked via GLVN_POOL_EXPAND_IF_NEEDED macro */
|
||
|
void glvn_pool_expand_mvals(void); /* invoked via ENSURE_GLVN_POOL_SPACE macro */
|
||
|
void op_glvnpop(uint4 indx); /* Used by [SET and $ORDER()] */
|
||
|
uint4 op_glvnslot(uint4 recycle); /* Used by [FOR, SET and $ORDER()] */
|
||
|
void op_indsavglvn(mval *target, uint4 slot, uint4 do_ref); /* Used by [SET and $ORDER()] */
|
||
|
void op_indsavlvn(mval *target, uint4 slot); /* Used by [FOR] */
|
||
|
void op_rfrshgvn(uint4 indx, opctype oc); /* Used by [SET and $ORDER()] */
|
||
|
lv_val *op_rfrshlvn(uint4 indx, opctype oc); /* Used by [FOR, SET and $ORDER()] */
|
||
|
void op_savgvn(UNIX_ONLY_COMMA(int argcnt) mval *val_arg, ...); /* Used by [SET and $ORDER()] */
|
||
|
void op_savlvn(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); /* Used by [FOR, SET and $ORDER()] */
|
||
|
void op_shareslot(uint4 indx, opctype opcode); /* Used by [FOR, SET and $ORDER()] */
|
||
|
void op_stoglvn(uint4 indx, mval *value); /* Used by [SET] */
|
||
|
|
||
|
#endif /* GLVN_POOL_H_INCLUDED */
|