/*
 * 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 <mom/c/pfe.hh>
#include <mom/libaoi.h>
#include <mom/c/libcast.h>
#include <mom/c/libpres_c.h>

#include "private.hh"

void pg_state::p_marshal_stub_conn(pres_c_marshal_stub *mstub,
				   int func_ref)
{
	cast_func_type *cfunc = &out_pres->stubs_cast.cast_scope_val[func_ref].
		u.cast_def_u_u.func_type;
	cast_func_param *cfield;
	int p;
	
	pres_c_mapping conn_ref_map;
	
	/* Build a C parameter in cfunc->params.params_val[p] that refers to
	   the marshal/unmarshal stream.  Note that the type of the `_stream'
	   argument is `flick_marshal_stream'.  This is an abstract type that
	   will be implemented by the runtime associated with the transport
	   that is eventually chosen.
	   
	   NOTE: It is an extremely bad idea to specialize this method within a
	   particular presentation generator.  If you do so (e.g., to change
	   the type of the `_stream' argument), then your new presentation
	   generator will produce code that can't be used with Flick's runtime
	   libraries.
	   
	   At one time, I thought that it would be a good idea to change the
	   type of `_stream' to be a C pointer.  This is actually a *bad* idea
	   because it constrains the possible ways in which the Flick runtimes
	   can implement streams.  A runtime might implement want to implement
	   `flick_marshal_stream_t' an an integer index into an array of
	   structres, for example.
	   
	   The only restriction that we impose here on the implementation of
	   `flick_marshal_stream_t' is that streams must be passable by value
	   to marshal and unmarshal functions.  Practically, this means that
	   `flick_marshal_stream_t' must be some kind of pointer or index to a
	   structure, but we don't *force* a choice by making `_stream' be a
	   pointer. */
	p = cast_func_add_param(cfunc);
	cfield = &cfunc->params.params_val[p];
	cfield->name = ir_strlit("_stream");
	cfield->type = cast_new_type_name("flick_marshal_stream_t");
	
	/* Make a reference mapping for the `cfield'. */
	/*
	 * XXX --- The `target_i' field for a marshal/unmarshal stub seems to
	 * be obsolete --- perhaps it is a holdover from some past time when
	 * m/u stubs received target object references?  Or was it simply
	 * intended to be a way to find the marshal stream argument (through
	 * the inline atom index `p')?
	 *
	 * In either case, `cfield' does not now refer to an object reference,
	 * so it is wrong to make a PRES_C_MAPPING_REFERENCE for it.  Let's
	 * make a PRES_C_MAPPING_IGNORE instead.
	 */
	conn_ref_map = pres_c_new_mapping(PRES_C_MAPPING_IGNORE);
	
	/* Finally, set the target inline (`target_i') for this stub.  The
           appropriate inline is an inline atom. */
	mstub->target_i = pres_c_new_inline_atom(p, conn_ref_map);
}

void pg_state::p_marshal_stub_data(cast_type ctype, pres_c_mapping map,
				   pres_c_stub_kind kind,
				   pres_c_marshal_stub *mstub,
				   int func_ref)
{
	cast_func_type *cfunc = &out_pres->stubs_cast.cast_scope_val[func_ref].
		u.cast_def_u_u.func_type;
	cast_func_param *cfield;
	pres_c_inline inl;
	int p;
	
	cfunc->return_type = cast_new_prim_type(CAST_PRIM_INT,0);
	
	/* Build a C parameter in cfunc->params.params_val[p] to refer to the
	   data to be marshaled/unmarshaled.  NOTE that the type of this
	   parameter will be modified later on in this function to be a pointer
	   to the data to be processed. */
	p = cast_func_add_param(cfunc);
	cfield = &cfunc->params.params_val[p];
	cfield->name = ir_strlit("_data");
	switch (kind) {
	case PRES_C_MARSHAL_STUB:
		cfield->type = ctype;
		break;
	case PRES_C_UNMARSHAL_STUB:
		cfield->type = ctype;
		break;
	default:
		panic("In `pg_state::p_marshal_stub_data', "
		      "the marshal stub type is unrecognized.");
		break;
	}
	
	/*
	 * Modify the parameter and mapping by inserting a level of indirection
	 * through a C pointer.
	 *
	 * We do *not* want allocation for indirection pointers (they are
	 * already provided to us correctly when params are passed by ref).
	 *
	 * Since m/u stubs are specialized by the back end, we must set each
	 * valid case.  UNKNOWN should never be associated with a generated m/u
	 * stub, so we set it to invalid.
	 */
	pres_c_allocation alloc;
	pres_c_allocation_u indir;

	indir.allow = PRES_C_ALLOCATION_ALLOW;
	indir.pres_c_allocation_u_u.val.flags
		= PRES_C_ALLOC_NEVER | PRES_C_DEALLOC_NEVER;
	indir.pres_c_allocation_u_u.val.allocator.kind
		= PRES_C_ALLOCATOR_DONTCARE;
	indir.pres_c_allocation_u_u.val.alloc_init = 0;
	
	alloc.cases[PRES_C_DIRECTION_IN]
		= alloc.cases[PRES_C_DIRECTION_INOUT]
		= alloc.cases[PRES_C_DIRECTION_OUT]
		= alloc.cases[PRES_C_DIRECTION_RETURN]
		= indir;
	
	alloc.cases[PRES_C_DIRECTION_UNKNOWN].allow
		= PRES_C_ALLOCATION_INVALID;
	
	pres_c_interpose_indirection_pointer(&(cfield->type), &map, alloc);
	
	/* Build a PRES_C inline atom for this parameter. */
	inl = pres_c_new_inline_atom(p, map);
	
	/* Save the inline that describes how to process the `_data' parameter
           along with the marshal/unmarshal stub's definition. */
	
	mstub->i = inl;
}

void pg_state::p_mu_stub(cast_type ctype_name, pres_c_mapping map,
			 mint_ref itype,
			 pres_c_stub_kind kind, char *func_name,
			 pres_c_mapping seethru_map)
{
	p_type_collection *ptc;
	p_type_node *ptn;
	int func_cdef;
	int stub;
	pres_c_marshal_stub *mstub;
	cast_type ctype;
	int aidx;
	
	/*
	 * Create the stub function declaration and stub mapping definition.
	 * Note that this much like a *template* for a stub.  If/when the back
	 * end decides a stub is necessary for this data type, it will generate
	 * a specialized stub (currently this means the direction will be
	 * known, and the allocation semantics will thus be correct).  This is
	 * why we set the inclusion flag to SUPPRESSED.
	 */
	cast_scoped_name scn = cast_new_scoped_name(func_name, NULL);
	aidx = aoi_get_parent_scope(in_aoi, cur_aoi_idx);
	func_cdef = cast_add_def(&out_pres->stubs_cast,
				 scn,
				 CAST_SC_NONE,
				 CAST_FUNC_DECL,
				 (pg_channel_maps[(gen_client)?
						 PG_CHANNEL_CLIENT_IMPL:
						 PG_CHANNEL_SERVER_IMPL]
				  [builtin_file]),
				 current_protection);
	stub = p_add_stub(out_pres);
	s(stub).kind = kind;
	mstub = &s(stub).pres_c_stub_u.mstub;
	mstub->c_func = func_cdef;
	mstub->itype = itype;
	mstub->seethru_map = seethru_map;
	
	/* Figure out how the stub will find the marshal/unmarshal stream. */
	p_marshal_stub_conn(mstub, func_cdef);
	
	/* Add a parameter pointing to the actual data to marshal. */
	p_marshal_stub_data(ctype_name, map, kind, mstub, func_cdef);
	
	ptc = p_type_collection::find_collection(&type_collections,
						 cur_aoi_idx);
	ptn = new p_type_node;
	ptn->set_flags(PTF_REF_ONLY|PTF_NO_REF);
	ptn->set_name((kind == PRES_C_MARSHAL_STUB) ?
		      "marshal_stub" :
		      "unmarshal_stub");
	ptn->set_format(func_name);
	ctype = cast_new_type(CAST_TYPE_FUNCTION);
	ctype->cast_type_u_u.func_type = out_pres->stubs_cast.
		cast_scope_val[func_cdef].u.cast_def_u_u.func_type;
	ptn->set_type(ctype);
	ptc->add_type("root", ptn, 1, 0);
	ptn->set_channel((pg_channel_maps[(gen_client)?
					 PG_CHANNEL_CLIENT_DECL:
					 PG_CHANNEL_SERVER_DECL]
			  [builtin_file]));
}

/* End of file. */



syntax highlighted by Code2HTML, v. 0.9.1