/*
 * Copyright (c) 1995, 1996, 1997, 1998, 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Flick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <assert.h>

#include <mom/compiler.h>
#include <mom/c/libcast.h>
#include <mom/c/libpres_c.h>
#include <mom/c/pbe.hh>

/*
 * This routine "inlines" a function call to a separate marshal/unmarshal stub,
 * if it is discovered that a PRES_C_MAPPING_STUB node can or should be inlined
 * (see `mu_state::mu_mapping_stub').
 *
 * The code inlining is done by calling the generic `pres_descend_mapping_stub'
 * routine, provided by libpres_c, to translate the "reference" ctype and
 * mapping (probably a CAST_TYPE_NAME and a PRES_C_MAPPING_STUB, respectively)
 * to the "actual" ctype and mapping they represent, by digging into the target
 * stub's definition.
 * 
 * How this happens is not something you want to know about; but once it's done
 * all we need to do is replace the old ctype and mapping with the new ones and
 * keep descending.
 */

void mu_state::mu_mapping_stub_inline(cast_expr expr,
				      cast_type ctype,
				      mint_ref itype,
				      pres_c_mapping map)
{
	assert(map->kind == PRES_C_MAPPING_STUB);
	// assert((op & MUST_ENCODE) || (op & MUST_DECODE));
	if (!((op & MUST_ENCODE) || (op & MUST_DECODE))) {
#if 0
		warn("Ignoring op %d in `mu_mapping_stub_inline'.", op);
#endif
		return;
	}
	
	/* XXX encode/decode? */
	
	/*
	 * XXX --- Start of the ``array slice hack,'' part 1.
	 *
	 * The code from here up to the call to `pres_descend_mapping_stub' is
	 * a hack for handling CORBA-style ``array slice'' presentations, in
	 * which an array type is presented as a pointer to the array's first-
	 * level element type.  (E.g., `int [5]' presented as `int *', and
	 * `int [4][5]' presented as `(int [5]) *').  This code also comes into
	 * play when `mu_server_func' transforms array parameter types into
	 * pointer-to-element types.
	 *
	 * The hack here is that we want to call the marshal stub associated
	 * with the array type, but the presented CAST type doesn't exactly
	 * match.  We have to ``promote'' our pointer type to the appropriate
	 * named array type in order for `pres_descend_mapping_stub' to work.
	 */
	cast_type ctype_temp = ctype;
	cast_type ctype_orig = 0;
	
	int is_pointer_to_array_slice = 0;
	
	while (ctype_temp->kind == CAST_TYPE_QUALIFIED)
		ctype_temp = ctype_temp->cast_type_u_u.qualified.actual;
	
	if (ctype_temp->kind == CAST_TYPE_POINTER) {
		/*
		 * Save our original-but-unqualified C type; we need this in
		 * order to get back on track later on.  Certain things, e.g.,
		 * `mu_mapping_fixed_array' care whether we are working with a
		 * pointer type or an array type.
		 */
		ctype_orig = ctype_temp;
		
		/*
		 * Find the marshal stub corresponding to the current MINT
		 * type (itype).  Note that `pres_c_find_mu_stub' doesn't
		 * examine the given `ctype' --- good thing, since we need to
		 * change it below (in order for `pres_descend_mapping_stub' to
		 * work).
		 */
		int stub_num = pres_c_find_mu_stub(pres, itype,
						   ctype_temp, map,
						   PRES_C_MARSHAL_STUB);
		pres_c_marshal_stub *mstub;
		cast_def *cfunc;
		
		if (stub_num < 0)
			panic("In `mu_state::mu_mapping_stub_inline', "
			      "can't find marshal stub for MINT type %d",
			      itype);
		
		mstub = &(pres->stubs.stubs_val[stub_num].pres_c_stub_u.
			  mstub);
		
		/*
		 * Check that the stub implements a fixed array mapping.
		 *
		 * XXX - We can't assert this easily anymore, since the
		 * allocation context is likely interposed here.  We'd
		 * have to dig pretty far just to see if it's a fixed
		 * array.  We'll just take it on faith at this point.
		 *
		assert(mstub->seethru_map->kind == PRES_C_MAPPING_FIXED_ARRAY);
		 */
		
		/* Get a pointer to the marshal function definition. */
		cfunc = &(pres->stubs_cast.cast_scope_val[mstub->c_func]);
		
		/*
		 * Get the type of the argument at index 1.  After we strip
		 * away the (known) pointer and any qualifiers, `ctype_temp'
		 * will be a named type, naming the array type.
		 *
		 * XXX --- Yes, we should dig through the stub's inline to find
		 * the index of the parameter that is to be marshaled, but
		 * we're already inside a hack.  Another hack can't hurt much.
		 */
		ctype_temp = cfunc->u.cast_def_u_u.func_type.
			     params.params_val[1].type;
		
		/* Dig down through the top-level pointer. */
		assert(ctype_temp->kind == CAST_TYPE_POINTER);
		ctype_temp = ctype_temp->cast_type_u_u.pointer_type.target;
		
		/* Dig down through any qualifiers. */
		while (ctype_temp->kind == CAST_TYPE_QUALIFIED)
			ctype_temp = ctype_temp->cast_type_u_u.qualified.
				     actual;
		
		/*
		 * Set `ctype' to the named type.  `pres_descend_mapping_stub'
		 * will effectively un-`typedef' the name later on, leaving us
		 * with the basic array type.
		 */
		ctype = ctype_temp;
		
		/*
		 * Remember that we are processing an array slice, so that we
		 * can make further hacks below.
		 */
		is_pointer_to_array_slice = 1;
	}
	/* XXX --- End of the ``array slice hack,'' part 1. */
	
	/* Descend into the stub and continue traversing the mapping tree. */
	pres_descend_mapping_stub(pres, itype, &ctype, &map);
	
	/*
	 * XXX --- Start of the ``array slice hack,'' part 2.
	 *
	 * First, if we had a pointer type when we came in, then get a pointer
	 * type again.  `mu_mapping_fixed_array' cares about the differences
	 * between arrays and pointers.
	 *
	 * Second, if we had a pointer type, and we are constructing a server
	 * dispatch function, assume that the current CAST expression refers
	 * to an operation parameter.  Munge the mapping for `in' and `inout'
	 * parameters so that their storage will be auto-allocated.  The map
	 * created by `p_fixed_array_type' always specifies some non-auto
	 * allocator, because it can't make different policies for different
	 * uses of a type.  (We used to munge the allocation flags, too, but
	 * now those are set correctly the the presentation generator.)
	 *
	 * It is probably a bad assumption to assume that only top-level
	 * parameter types get munged between array types and pointer types,
	 * but this is true for all currently implemented presentation styles.
	 */
	if (is_pointer_to_array_slice
	    && (ctype_orig->kind == CAST_TYPE_POINTER)) {
		assert(ctype->kind == CAST_TYPE_ARRAY);
		ctype = cast_new_pointer_type(ctype->cast_type_u_u.array_type.
					      element_type);
	}
#if 0
	/*
	 * XXX --- We no longer need to "fix" the allocator.  The presentation
	 * generator now specifies different policies for different uses of
	 * a type, and thus it defaults to DONTCARE (`auto') appropriately.
	 */
	if (is_pointer_to_array_slice
	    && (ctype->kind == CAST_TYPE_POINTER)
	    && (!strcmp(which_stub, "server"))
	    && (current_param_dir != PRES_C_DIRECTION_RETURN)
	    && (current_param_dir != PRES_C_DIRECTION_UNKNOWN)) {
		/*
		 * Construct a fixed array mapping with `auto' allocation.
		 * Trust that the presentation generator set the allocation
		 * flags correctly.
		 */
		pres_c_mapping new_map
			= pres_c_new_mapping(PRES_C_MAPPING_FIXED_ARRAY);
		
		*new_map = *map;
		new_map->pres_c_mapping_u_u.fixed_array.alloc.allocator
			= "auto";
		
		map = new_map;
	}
#endif
#if 0
	/*
	 * XXX --- We used to do this, before the presentation generator was
	 * changed to emit the correct allocation flags.
	 */
	/*
	 * The function `p_mapping_fixed_array' in the presentation generator
	 * library always specifies (PRES_C_ALLOC_NEVER | PRES_C_DEALLOC_NEVER)
	 * allocation semantics, because it can't specify different policies
	 * for different *uses* of a single type.  So here we fix the flags,
	 * based on the current parameter direction and stub kind.
	 *
	 * Note that this code is similar to what you would find in the various
	 * `p_param_type' methods in the presentation generators.  But those
	 * methods can't change the allocation flags like we can, because they
	 * can't ``reach inside'' a stub mapping for a named type.  We can, by
	 * returning a mapping that is slightly different from the mapping
	 * found by `pres_descend_mapping_stub'.
	 */
	if (is_pointer_to_array_slice
	    && ((current_param_dir == PRES_C_DIRECTION_OUT)
		|| (current_param_dir == PRES_C_DIRECTION_RETURN))) {
		/*
		 * Construct a fixed array mapping with the flags we need for
		 * an `out' or `return' parameter.  Copy the `seethru_map' that
		 * we got from the stub, but change the pointer allocation.
		 */
		pres_c_mapping new_map
			= pres_c_new_mapping(PRES_C_MAPPING_FIXED_ARRAY);
		
		*new_map = *map;
		if (!strcmp(which_stub, "client")) {
			new_map->pres_c_mapping_u_u.fixed_array.alloc.flags
				= (PRES_C_ALLOC_ALWAYS | PRES_C_DEALLOC_NEVER);
		} else if (!strcmp(which_stub, "server")) {
			new_map->pres_c_mapping_u_u.fixed_array.alloc.flags
				= (PRES_C_ALLOC_NEVER | PRES_C_DEALLOC_ALWAYS);
		} else
			panic("In `mu_state::mu_mapping_stub_inline', "
			      "generating neither client stub nor server "
			      "skeleton.");
		
		map = new_map;
	}
#endif
	/* XXX --- End of the ``array slice hack,'' part 2. */
	
	mu_mapping(expr, ctype, itype, map);
}

/* End of file. */



syntax highlighted by Code2HTML, v. 0.9.1