/****************************************************************
 *								*
 *	Copyright 2001, 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_string.h"

#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "stringpool.h"
#include "op.h"
#include "gdskill.h"		/* needed for tp.h */
#include "gdscc.h"		/* needed for tp.h */
#include "filestruct.h"		/* needed for tp.h */
#include "jnl.h"		/* needed for tp.h */
#include "buddy_list.h"		/* needed for tp.h */
#include "hashtab_int4.h"	/* needed for tp.h */
#include "tp.h"
#include "process_gvt_pending_list.h"

GBLREF	gd_binding	*gd_map;
GBLREF	gd_region	*gv_cur_region;
GBLREF	gv_key		*gv_currkey;
GBLREF	gv_namehead	*gv_target;
GBLREF	spdesc		stringpool;
GBLREF  uint4           dollar_tlevel;
GBLREF	sgm_info	*first_sgm_info, *sgm_info_ptr;

void op_gvsavtarg(mval *v)
{
	int			len, align_len;
	unsigned char		*c;
	DEBUG_ONLY(
		unsigned char	*tmpc;
	)
	short			end;
	gvsavtarg_t		*gvsavtarg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC;
	DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC;
	v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by this to-be-overwritten mval */
	if (NULL == gv_currkey)
	{	/* Simplest case, finish it off */
		v->str.len = 0;
		v->mvtype = MV_STR;
		return;
	}
	assert(NULL != TREF(gd_targ_addr));
	assert((NULL != gv_target) || (0 == gv_currkey->end));
	/* The way savtarg/rectarg works is by saving and restoring a copy of "gv_target". This assumes that once gv_target
	 * has been allocated and used in a savtarg, the memory is never freed at least until the rectarg is completed.
	 * gvtargets in the pending list could be freed and reallocated so such gvtargets should never be the current
	 * "gv_target" global in case we are in savtarg (or else at rectarg time the saved gv_target could have been freed).
	 * Assert accordingly.
	 */
	assert((NULL == gv_target) || !is_gvt_in_pending_list(gv_target));
	end = gv_currkey->end;
	len = (int)(end + GVSAVTARG_FIXED_SIZE);
	align_len = len + (GVSAVTARG_ALIGN_BNDRY - 1); /* is for 8-byte alignment of v->str.addr */
	ENSURE_STP_FREE_SPACE(align_len);
	v->str.len = len;
	c = (unsigned char *)(ROUND_UP2((UINTPTR_T)stringpool.free, GVSAVTARG_ALIGN_BNDRY));
	assert((c + len) <= (stringpool.free + align_len));
	v->str.addr = (char *)c;
	v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
	stringpool.free += align_len;
	gvsavtarg = (gvsavtarg_t *)c;
	/* Now we are going to fill in the structure fields most of which are pointer fields (size upto 8-byte).
	 * This is why we ensure 8-byte alignment of c before typecasting it into gvsavtarg.
	 */
	DEBUG_ONLY(
		assert(!dollar_tlevel || (NULL != first_sgm_info) || (NULL == sgm_info_ptr));
		if (dollar_tlevel && (NULL != sgm_info_ptr))
			DBG_CHECK_IN_FIRST_SGM_INFO_LIST(sgm_info_ptr);
	)
	gvsavtarg->gd_targ_addr = TREF(gd_targ_addr);
	gvsavtarg->gd_map = gd_map;
	gvsavtarg->gv_cur_region = gv_cur_region;
	gvsavtarg->gv_target = gv_target;
	gvsavtarg->gv_last_subsc_null = TREF(gv_last_subsc_null);
	gvsavtarg->gv_some_subsc_null = TREF(gv_some_subsc_null);
	gvsavtarg->prev = gv_currkey->prev;
	gvsavtarg->end = end;
	c += GVSAVTARG_FIXED_SIZE;
	if (0 < end)
	{
		assert(KEY_DELIMITER != gv_currkey->base[0]);
		assert(KEY_DELIMITER == gv_currkey->base[end - 1]);
		assert(KEY_DELIMITER == gv_currkey->base[end]);
		memcpy(c, gv_currkey->base, end);
	}
	return;
}
