1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
/****************************************************************
* *
* Copyright 2001, 2014 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. *
* *
****************************************************************/
#include "mdef.h"
#include <stdarg.h>
#include "gtm_string.h"
#include "gtm_stdio.h"
#include "gtmio.h"
#include "lv_val.h"
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "op.h"
#include <rtnhdr.h>
#include "stack_frame.h"
#include "alias.h"
#include "error.h"
GBLREF lv_xnew_ref *xnewref_anchor;
GBLREF lv_xnew_var *xnewvar_anchor;
GBLREF stack_frame *frame_pointer;
GBLREF symval *curr_symval;
GBLREF uint4 lvtaskcycle;
GBLREF unsigned char *stackbase, *msp;
STATICDEF stack_frame *fp_save;
STATICFNDCL void guard_against_zbzst(void);
CONDITION_HANDLER(zbreak_zstep_xnew_ch);
/* Exclusive new - Operation:
*
* 1) Push a new symtab onto the stack via mv_stent entry
* 2) For each var name listed that is not to be NEW'd:
* a) lookup the var in the old symbol table (create if does not exist)
* b) add the symbol to the new symbol table.
* c) copy the lv_val address from the old symbol table to the new symbol
* table.
* d) save the var name in a chain off of the symtab so we know which vars
* need special alias consideration processing when the symtab pops
* in umw_mv_stent().
*/
void op_xnew(UNIX_ONLY_COMMA(unsigned int argcnt_arg) mval *s_arg, ...)
{
boolean_t added;
ht_ent_mname *tabent1, *tabent2;
hash_table_mname *htold, *htnew;
int argcnt;
int4 shift;
lv_val *lvp, *lvtab1;
lv_xnew_var *xnewvar;
mval *s;
va_list var;
var_tabent lvent;
VMS_ONLY(va_count(argcnt));
UNIX_ONLY(argcnt = argcnt_arg); /* need to preserve stack copy on i386 */
htold = &curr_symval->h_symtab;
shift = symbinit();
DBGRFCT((stderr, "\n\n****op_xnew: **** New symbol table (0x"lvaddr") replaced previous table (0x"lvaddr")\n\n",
curr_symval, curr_symval->last_tab));
if (0 >= argcnt)
{
if (shift)
guard_against_zbzst();
return;
}
INCR_LVTASKCYCLE; /* So we don't process referenced base vars more than once */
htnew = &curr_symval->h_symtab;
assert(curr_symval->last_tab);
assert(htold == &curr_symval->last_tab->h_symtab);
VAR_START(var, s_arg);
s = s_arg;
for ( ; ; )
{
if ((unsigned char *)s >= msp && (unsigned char *)s < stackbase)
s = (mval*)((char*)s - shift); /* Only if stack resident */
lvent.var_name.len = s->str.len;
lvent.var_name.addr = s->str.addr;
if (MAX_MIDENT_LEN < lvent.var_name.len)
lvent.var_name.len = MAX_MIDENT_LEN;
COMPUTE_HASH_MNAME(&lvent);
lvent.marked = FALSE;
if (add_hashtab_mname_symval(htold, &lvent, NULL, &tabent1))
lv_newname(tabent1, curr_symval->last_tab);
lvtab1 = (lv_val *)tabent1->value;
assert(lvtab1);
assert(LV_IS_BASE_VAR(lvtab1));
added = add_hashtab_mname_symval(htnew, &lvent, NULL, &tabent2);
if (added)
{ /* This var has NOT been specified twice */
tabent2->value = tabent1->value;
lvp = (lv_val *)tabent2->value; /* Same lv_val pointed to by both hashtabs */
if (lvp && (IS_ALIASLV(lvp) || lvp->has_aliascont))
curr_symval->alias_activity = TRUE; /* Loading an alias into new symtab counts as
* activity! */
if (NULL != xnewvar_anchor)
{ /* Reuse entry from list */
xnewvar = xnewvar_anchor;
xnewvar_anchor = xnewvar->next;
} else
xnewvar = (lv_xnew_var *)malloc(SIZEOF(lv_xnew_var));
xnewvar->key = tabent1->key; /* Note "value" in this key is not used since it is not sync'd */
xnewvar->lvval = lvtab1;
xnewvar->next = curr_symval->xnew_var_list;
curr_symval->xnew_var_list = xnewvar;
INCR_CREFCNT(lvtab1);
INCR_TREFCNT(lvtab1);
/* Note that there is no attempt to prevent double processing an lvval that has been indicated
* through more than one (aliased) var being passed through. This is because these vars could be
* independent by the time they come back through when the symtab pops. So we will handle them the
* same way then.
*/
lvtab1->stats.lvtaskcycle = lvtaskcycle;
} else
/* Apparently var was specified twice -- better have value set as we expect it */
assert(tabent1->value == tabent2->value);
if (0 < --argcnt)
s = va_arg(var, mval*);
else
break;
}
va_end(var);
/* Now that all the passed-thru vars have been identified and recorded, go through them again to process their arrays
* and search for containers pointing to other arrays that we need to record.
*/
if (curr_symval->alias_activity)
{
for (xnewvar = curr_symval->xnew_var_list; xnewvar; xnewvar = xnewvar->next)
{
lvtab1 = xnewvar->lvval;
XNEWREF_CNTNRS_IN_TREE(lvtab1); /* note macro has LV_GET_CHILD exists check */
}
}
if (shift)
guard_against_zbzst();
return;
}
CONDITION_HANDLER(zbreak_zstep_xnew_ch)
{
START_CH(TRUE);
frame_pointer = fp_save;
NEXTCH;
}
STATICFNDEF void guard_against_zbzst(void)
{ /* if the new symbol table slid into the stack, then we guard against ZBREAK and ZSTEP having taken us to the xnew
* this could be done sligthly more efficiently and with stronger asserts using custom code, but this is an edge case,
* so we use, with an empty argument list, gtm_fetch et al to do the job
*/
boolean_t fetch;
stack_frame *fp, *fp_prev;
fp = frame_pointer;
assert(!(fp->type & SFT_COUNT));
fp_prev = fp->old_frame_pointer;
assert(fp_prev);
fetch = (fp->type & (SFT_ZBRK_ACT | SFT_ZSTEP_ACT));
while (!(fp_prev->type & SFT_COUNT))
{ /* find where we put the new symbol table like we did in symbinit but with additional checking on frame types */
fp = fp_prev;
fetch |= (fp->type & (SFT_ZBRK_ACT | SFT_ZSTEP_ACT));
fp_prev = fp->old_frame_pointer;
assert(fp_prev);
}
if (fetch)
{ /* only need to fetch if there is a zbreak or zstep frame in between our current position and the adjusted frame
* all other non SFT_COUNT frames either require a quit (SFT_ZINTR & SFT_TRIGR) which unstacks the symbol table
* protected by the NEW, or return to the beginning of the line (SFT_REP_OP & SFT_DEV_ACT & SFT_ZTRAP) which cause
* a refetch, or vector to a new virtual line (SFT_ZTRAP, but for $ZTRAP)
*/
ESTABLISH(zbreak_zstep_xnew_ch);
fp_save = frame_pointer;
frame_pointer = fp_prev; /* pretend we're in the original frame */
UNIX_ONLY(gtm_fetch(0, 0)); /* refetch everything in the old table into the new one */
VMS_ONLY(fetch_all()); /* call an assembly interlude so VMS gets to gtm_fetch */
frame_pointer = fp_save; /* restore the proper frame_pointer */
REVERT;
}
}
|