/**************************************************************** * * * Copyright 2010, 2011 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 "gtm_stdio.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "op.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" #include "min_max.h" GBLREF stack_frame *frame_pointer; GBLREF symval *curr_symval; GBLREF uint4 dollar_tlevel; GBLREF lv_val *active_lv; GBLREF mval *alias_retarg; /* Operation - The destination variable becomes a new alias of the data pointed to by the source container variable: * * 1) Index into the variable name table to get the variable name for the new alias (destination). * 2) Create the hash for the variable and look up in hash table (adding if not yet created). * 3) See if hash entry has a value pointer. If yes and same as source var, we are done (NOOP). * 4) Set hash entry to point to new lv_val. * 5) Whichever symval of source container or the alias it pointed to has the largest address, that symval is the * earliest symval affected by this alias action. Mark all interveening symvals (end points included) as having * had alias activity via MARK_ALIAS_ACTIVE macro. This is so we can properly handle issues in an exlusive NEW * situation involving multiple symvals and potential aliasing between them. * * Note that this opcode's function is very similar to "op_setalsctin2als" but is necessarily different because the * source container is in a temporary mval passed back through a function rather than the lv_val that "op_setalsctin2als" * deals with. Consequently, the amount of verification we can do is reduced. But this is acceptable due to the checks * done by "unw_retarg" and "op_exfunretals" which pre-processed this value for us. There is also different reference * count maintenance to do than the "op_setalsctin2als" opcode. With substantially more work to reorganize how SET * operates, it would likely be possible to combine these functions but the way things are structured now, all the * set functions plus "op_sto" share the same API so adding a parm to one means adding a useless parm to all 6 of * them which is not acceptable so we end up duplicating portions of code here. */ void op_setfnretin2als(mval *srcmv, int destindx) { ht_ent_mname *tabent; mname_entry *varname; lv_val *srclvc, *dstlv; int4 srcsymvlvl; boolean_t added; error_def(ERR_ALIASEXPECTED); assert(alias_retarg == srcmv); assert(srcmv); assert(srcmv->mvtype & MV_ALIASCONT); /* Verify is a temp mval */ assert((char *)srcmv >= (char *)frame_pointer->temps_ptr && (char *)srcmv < ((char *)frame_pointer->temps_ptr + (SIZEOF(char *) * frame_pointer->temp_mvals))); srclvc = (lv_val *)srcmv->str.addr; assert(srclvc); assert(LV_IS_BASE_VAR(srclvc)); /* Verify base var */ assert(srclvc->stats.trefcnt >= srclvc->stats.crefcnt); assert(1 <= srclvc->stats.crefcnt); /* Verify we have an existing container reference */ srcsymvlvl = LV_SYMVAL(srclvc)->symvlvl; /* lv_val may go away below so record symlvl */ varname = &(((mname_entry *)frame_pointer->vartab_ptr)[destindx]); DEBUG_ONLY(added = FALSE); /* Find hash table entry */ if (NULL == (tabent = (ht_ent_mname *)frame_pointer->l_symtab[destindx])) /* note tabent assignment */ { /* No fast path to hash table entry -- look it up the hard(er) way */ varname = &(((mname_entry *)frame_pointer->vartab_ptr)[destindx]); added = add_hashtab_mname_symval(&curr_symval->h_symtab, varname, NULL, &tabent); } assert(tabent); assert(tabent || added); dstlv = (lv_val *)tabent->value; if (NULL == dstlv && curr_symval->tp_save_all) { /* dstlv does not exist yet we need to be able to save a previous "novalue" lvval in case a TPRESTART needs to restore the value. Create a var so its undefined status can be saved. */ lv_newname(tabent, curr_symval); dstlv = (lv_val *)tabent->value; assert(dstlv); } /* No need to increment before dstlv processing to prevent removal of last reference to srclvc in this case because * the increment has already been done in "unw_retarg". */ if (dstlv) { assert(LV_IS_BASE_VAR(dstlv)); /* Verify base var */ if (dollar_tlevel && NULL != dstlv->tp_var && !dstlv->tp_var->var_cloned) TP_VAR_CLONE(dstlv); assert(0 < dstlv->stats.trefcnt); assert(0 < (dstlv->stats.trefcnt - dstlv->stats.crefcnt)); /* Make sure there is one non-container reference */ DECR_TREFCNT(dstlv); assert(dstlv->stats.trefcnt >= dstlv->stats.crefcnt); if (0 == dstlv->stats.trefcnt) { /* Non alias -- make room for an alias to live here instead */ lv_kill(dstlv, DOTPSAVE_TRUE, DO_SUBTREE_TRUE); LV_FREESLOT(dstlv); } /* Else alias pointer in the hash table is just replaced below */ } DECR_CREFCNT(srclvc); /* In "unw_retarg" we incremented for a container but is now "just" an alias so get rid of * the container count from the temp return parm */ frame_pointer->l_symtab[destindx] = tabent; DBGRFCT((stderr, "op_setfnret2als: hte 0x"lvaddr" being reset from 0x"lvaddr" to 0x"lvaddr"\n", tabent, tabent->value, srclvc)); tabent->value = (void *)srclvc; /* These symvals have had alias activity - Note the possibility of re-marking srcsymvlvl is not necessarily re-doing * the mark done by "unw_retarg" since the source lv_val may have been re-created if it was originally in an xnew'd * symtab which popped during the return. */ MARK_ALIAS_ACTIVE(MIN(srcsymvlvl, LV_SYMVAL(srclvc)->symvlvl)); active_lv = (lv_val *)NULL; /* if we get here, subscript set was successful. clear active_lv to avoid later cleanup problems */ alias_retarg = NULL; }