/*
* 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 <string.h>
#include <assert.h>
#include <mom/compiler.h>
#include <mom/libaoi.h>
#include <mom/libmint.h>
#include <mom/c/pfe.hh>
#include <mom/c/libcast.h>
#include <mom/c/libpres_c.h>
#include "private.hh"
void pg_state::p_server_func_make_decl(aoi_interface */*ai*/,
aoi_operation *ao,
char *opname,
cast_func_type *cfunc)
{
cast_ref cr;
cast_scope *scope = (cast_scope *)top_ptr(scope_stack);
cast_scope *deep_scope = scope;
cast_scoped_name scn = cast_new_scoped_name(opname, NULL);
if( (ao->flags & (AOI_OP_FLAG_GETTER|AOI_OP_FLAG_SETTER)) ||
(cr = cast_find_def(&deep_scope,
scn,
CAST_FUNC_DECL)) == -1 ) {
cr = cast_add_def(scope,
scn,
CAST_SC_NONE,
CAST_FUNC_DECL,
ch(cur_aoi_idx, PG_CHANNEL_SERVER_DECL),
current_protection);
scope->cast_scope_val[cr].u.cast_def_u_u.func_type = *cfunc;
scope->cast_scope_val[cr].u.cast_def_u_u.func_type.spec =
server_func_spec;
} else {
if( out_pres->meta_data.channels.
channels_val[scope->cast_scope_val[cr].channel].input !=
a(cur_aoi_idx).idl_file )
scope->cast_scope_val[cr].channel =
ch(cur_aoi_idx, PG_CHANNEL_SERVER_DECL);
}
}
/*
* Generate a server work function presentation for an AOI interface operation.
*/
pres_c_func pg_state::p_server_func(aoi_interface *ai,
aoi_operation *ao)
{
pres_c_func func;
func.kind = PRES_C_SERVER_FUNC;
pres_c_server_func *server_func = &func.pres_c_func_u.sfunc;
char *old_name;
char *opname;
int cast_params_len;
int cdef;
cast_func_type cfunc;
stub_special_params specials;
int i, j;
mint_ref request_ref;
mint_ref reply_ref;
mint_const oper_request;
mint_const oper_reply;
/*****/
if(!lookup_interface_mint_discrims(ai, ao,
&oper_request, &oper_reply)) {
panic("In `pg_state::p_server_func', "
"cannot find MINT request and reply discriminators.");
}
/*
* Find the MINT references to the request and reply types.
*/
p_server_func_find_refs(ai, ao, oper_request, oper_reply,
&request_ref,
&reply_ref);
/*
* Determine the special parameters for this function: the target
* object reference, the environment reference, etc.
*/
p_server_func_special_params(ao, &specials);
/*
* Determine the total number of function parameters.
*/
cast_params_len = ao->params.params_len;
for (i = 0;
i < stub_special_params::number_of_stub_special_param_kinds;
++i)
if (specials.params[i].index != -1)
++cast_params_len;
/*
* Verify our set of special parameters.
*/
for (i = 0;
i < stub_special_params::number_of_stub_special_param_kinds;
++i) {
if (specials.params[i].index != -1) {
/*
* Assert that this special parameter has a valid
* CAST type and a valid, unique index.
*/
assert(specials.params[i].ctype != 0);
assert((specials.params[i].index >= 0)
&& (specials.params[i].index
< cast_params_len));
for (j = i + 1;
j < stub_special_params::
number_of_stub_special_param_kinds;
++j)
assert(specials.params[i].index
!= specials.params[j].index);
}
}
/* Save the original name context for when we return. */
old_name = name;
name = calc_server_func_name(ao->name);
opname = name;
/*
* Now we are ready to start building the presentation PRES_C and CAST
* goo.
*/
cast_init_function_type(&cfunc, cast_params_len);
/*
* Build the group of pres_c_inline structures containing the
* parameters, starting with level 4 (params struct) then levels
* 3, 2, 1 (unions).
*
* KBF --- the L4 reply inline is no long a struct, it's a UNION of 3
* items:
* 0 - the old reply params struct
* 1 - union of all user defined exceptions that this operation
* supports
* -1 - a system exception (out of memory, etc.)
*/
pres_c_inline request_l4_inl = pres_c_new_inline_func_params_struct(0);
pres_c_inline reply_l4_inl = pres_c_new_inline_func_params_struct(0);
pres_c_inline target_inl = pres_c_new_inline(PRES_C_INLINE_ATOM);
pres_c_mapping return_mapping;
cast_type return_ctype;
pres_c_mapping alloc_return_mapping;
process_server_params(&cfunc,
&specials,
request_ref, reply_ref,
ao,
request_l4_inl, reply_l4_inl,
target_inl, 0 /* no client */);
/*
* Now process the return type.
*
* An inline atom index of `-1' indicates a return value.
* The MINT type of the return value is stored in the last slot of the
* reply structure (thus, the hairy expression for the second argument
* in the call below). See `tam_operation_reply_struct' in the file
* `aoi_to_mint.c' for more information.
*
* KBF - This is now in a UNION before the structure...
*/
mint_ref reply_struct_ref = (m(reply_ref).mint_def_u.union_def.
cases.cases_val[0].var);
p_server_func_return_type(ao,
(m(reply_struct_ref).mint_def_u.struct_def.
slots.
slots_val[m(reply_struct_ref).mint_def_u.
struct_def.slots.slots_len - 1]),
&return_ctype,
&return_mapping);
p_server_func_alloc_return(return_ctype,
&alloc_return_mapping);
cfunc.return_type = return_ctype;
p_server_func_make_decl(ai, ao, opname, &cfunc);
cdef = cast_add_def(&out_pres->stubs_cast,
calc_server_func_scoped_name(cur_aoi_idx, opname),
CAST_SC_NONE,
CAST_FUNC_DECL,
ch(cur_aoi_idx, PG_CHANNEL_SERVER_IMPL),
current_protection);
out_pres->stubs_cast.cast_scope_val[cdef].u.
cast_def_u_u.func_type = cfunc;
server_func->c_func = cdef;
server_func->op_flags = PRES_C_STUB_OP_FLAG_NONE;
/* Determine if the operation is oneway. */
if (ao->flags & AOI_OP_FLAG_ONEWAY)
server_func->op_flags |= PRES_C_STUB_OP_FLAG_ONEWAY;
/*
* Allocate and set the return value slot in the PRES_C `reply_l4_inl'.
* The MINT type for the return value is always the last slot in the
* reply's MINT struct type.
*
* Additionally, set the request `return_slot' to a PRES_C tree that
* will cause the BE to allocate a ``root'' for the return value.
*/
reply_l4_inl->
pres_c_inline_u_u.func_params_i.return_slot
= ((pres_c_inline_struct_slot *)
mustmalloc(sizeof(*(reply_l4_inl->
pres_c_inline_u_u.func_params_i.
return_slot))));
reply_l4_inl->
pres_c_inline_u_u.func_params_i.return_slot->
mint_struct_slot_index
= (m(reply_struct_ref).mint_def_u.struct_def.slots.slots_len
- 1);
reply_l4_inl->
pres_c_inline_u_u.func_params_i.return_slot->
inl
= pres_c_new_inline_atom(pres_c_func_return_index,
return_mapping);
request_l4_inl->pres_c_inline_u_u.func_params_i.return_slot
= ((pres_c_inline_struct_slot *)
mustmalloc(sizeof(*(request_l4_inl->
pres_c_inline_u_u.func_params_i.
return_slot))));
request_l4_inl->
pres_c_inline_u_u.func_params_i.return_slot->
mint_struct_slot_index
= mint_slot_index_null;
request_l4_inl->
pres_c_inline_u_u.func_params_i.return_slot->
inl
= pres_c_new_inline_atom(pres_c_func_return_index,
alloc_return_mapping);
/*
* We need to turn the reply into the union of good, bad, & ugly values
*/
p_do_return_union(ao, &reply_l4_inl, reply_ref, cdef,
specials.params[stub_special_params::
environment_ref].index);
/*
* level 3
*
* XXX - might need to modify the operation request code here,
* e.g. add a prefix in the CORBA case (perhaps in overriding
* function)
*/
pres_c_inline request_l3_inl =
pres_c_new_inline(PRES_C_INLINE_COLLAPSED_UNION);
request_l3_inl->pres_c_inline_u_u.collapsed_union.discrim_val =
oper_request;
request_l3_inl->pres_c_inline_u_u.collapsed_union.selected_case =
request_l4_inl;
pres_c_inline reply_l3_inl =
pres_c_new_inline(PRES_C_INLINE_COLLAPSED_UNION);
reply_l3_inl->pres_c_inline_u_u.collapsed_union.discrim_val =
oper_reply;
reply_l3_inl->pres_c_inline_u_u.collapsed_union.selected_case =
reply_l4_inl;
/* level 2 */
pres_c_inline request_l2_inl =
pres_c_new_inline(PRES_C_INLINE_COLLAPSED_UNION);
request_l2_inl->pres_c_inline_u_u.collapsed_union.discrim_val =
mint_new_const_from_aoi_const(ai->code);
request_l2_inl->pres_c_inline_u_u.collapsed_union.selected_case =
request_l3_inl;
pres_c_inline reply_l2_inl =
pres_c_new_inline(PRES_C_INLINE_COLLAPSED_UNION);
reply_l2_inl->pres_c_inline_u_u.collapsed_union.discrim_val =
mint_new_const_from_aoi_const(ai->code);
reply_l2_inl->pres_c_inline_u_u.collapsed_union.selected_case =
reply_l3_inl;
/* level 1 */
pres_c_inline request_l1_inl =
pres_c_new_inline(PRES_C_INLINE_COLLAPSED_UNION);
request_l1_inl->pres_c_inline_u_u.collapsed_union.discrim_val =
mint_new_const_int((int)ai->idl);
request_l1_inl->pres_c_inline_u_u.collapsed_union.selected_case =
request_l2_inl;
pres_c_inline reply_l1_inl =
pres_c_new_inline(PRES_C_INLINE_COLLAPSED_UNION);
reply_l1_inl->pres_c_inline_u_u.collapsed_union.discrim_val =
mint_new_const_int((int)ai->idl);
reply_l1_inl->pres_c_inline_u_u.collapsed_union.selected_case =
reply_l2_inl;
/* Assign the unions and param struct to server_func fields. */
server_func->request_i = request_l1_inl;
server_func->reply_i = reply_l1_inl;
/* Set the target_i field. */
server_func->target_i = target_inl;
server_func->target_itype =
out_pres->mint.standard_refs.interface_name_ref;
/* Set the client_i field. */
server_func->client_i = 0;
server_func->client_itype = mint_ref_null;
/* Set the error_i field. */
server_func->error_i = 0;
server_func->error_itype = mint_ref_null;
/* Restore the name context. */
name = old_name;
return func;
}
/*****************************************************************************/
/***** Auxiliary functions. *****/
void pg_state::p_server_func_special_params(aoi_operation *ao,
stub_special_params *specials)
{
stub_special_params::stub_param_info *this_param;
int i;
/*
* Initialize all of our special parameter data, just in case we fail
* to initialize any individual parameter below.
*/
for (i = 0;
i < stub_special_params::number_of_stub_special_param_kinds;
++i) {
specials->params[i].spec = 0;
specials->params[i].name = 0;
specials->params[i].ctype = 0;
specials->params[i].index = -1;
}
/*
* Initialize the object reference type and index. The default is for
* the object reference to appear as the first parameter.
*/
this_param = &(specials->params[stub_special_params::object_ref]);
this_param->name =
calc_server_func_object_param_name(ao->name);
this_param->ctype = cast_new_type_name(
calc_server_func_object_type_name(ao->name));
this_param->index = 0;
/*
* Initialize the environment reference type and index. The default is
* for the environment reference not to appear. We set the CAST type
* anyway for the possible benefit of derived presentation generators.
*/
this_param = &(specials->params[stub_special_params::environment_ref]);
this_param->name =
/*
* XXX --- Don't use `ao->name' until `pg_corba::p_get_
* exception_discrim_name' et al. have access to the operation
* name, too.
*/
calc_server_func_environment_param_name("");
this_param->ctype = cast_new_type_name(
/*
* XXX --- Don't use `ao->name' until `pg_corba::p_get_env_
* struct_type' has access to the operation name, too.
*/
calc_server_func_environment_type_name(""));
this_param->index = -1;
/*
* Initialize the (effective) client SID type and index. The default
* is for client SID to appear after all of the normal parameters if
* `gen_sids' is true. Otherwise, the client SID does not appear.
*/
this_param = &(specials->params[stub_special_params::client_sid]);
this_param->name =
calc_server_func_client_sid_param_name(ao->name);
this_param->ctype = cast_new_type_name(
calc_server_func_client_sid_type_name(ao->name));
if (gen_sids)
this_param->index = (ao->params.params_len + 1);
else
this_param->index = -1;
/*
* Initialize the required server SID type and index. The default is
* for the required server SID to appear after the client SID if
* `gen_sids' is true. Otherwise, the required server SID does not
* appear.
*/
this_param = &(specials->params[stub_special_params::
required_server_sid]);
this_param->name =
calc_server_func_required_server_sid_param_name(ao->name);
this_param->ctype = cast_new_type_name(
calc_server_func_server_sid_type_name(ao->name));
if (gen_sids)
this_param->index = (ao->params.params_len + 2);
else
this_param->index = -1;
/*
* Initialize the actual server SID type and index. The default is for
* the actual server SID not to appear --- even if `gen_sids' is
* specified. The underlying transport system, not the server itself,
* is responsible for supplying the server's actual SID to the client.
*/
this_param = &(specials->params[stub_special_params::
actual_server_sid]);
this_param->name =
calc_server_func_actual_server_sid_param_name(ao->name);
this_param->ctype = cast_new_type_name(
calc_server_func_server_sid_type_name(ao->name));
this_param->index = -1;
/* Finally, we're done! */
}
/*
* This method determines how `p_server_func' processes the return type of a
* server work function. Some presentation generators override this method.
*/
void pg_state::p_server_func_return_type(aoi_operation *ao, mint_ref /*mr*/,
cast_type *out_ctype,
pres_c_mapping *out_mapping)
{
p_type_collection *ptc = 0;
p_type_node *ptn;
/* Compute the basic C type and PRES_C mapping. */
p_type(ao->return_type, &ptc);
ptn = ptc->find_type("definition");
*out_ctype = ptn->get_type();
*out_mapping = ptn->get_mapping();
/* Tell the back end that this is the ``root'' of the parameter. */
pres_c_interpose_param_root(out_mapping, 0, 0);
/* Tell the back end that this is a return parameter. */
pres_c_interpose_direction(out_mapping, AOI_DIR_RET);
}
/*
* This method determines how `p_server_func' will add PRES_C nodes to the
* request PRES_C tree in order to cause the back end to allocate and perhaps
* initialize storage for the return value of an operation.
*/
void pg_state::p_server_func_alloc_return(cast_type return_ctype,
pres_c_mapping *out_mapping)
{
cast_type actual_ctype;
cast_expr zero_cexpr;
/* ``Dereference'' the type, just to be paranoid. */
actual_ctype
= cast_find_typedef_type(
((cast_scope *) top_ptr(scope_stack)),
return_ctype);
if (!actual_ctype)
/* Can't look it up? Use the `return_ctype' then. */
actual_ctype = return_ctype;
if (actual_ctype->kind == CAST_TYPE_VOID) {
/*
* Special case: the return type is `void'. The server should
* not allocate storage for the void return value.
*/
*out_mapping = pres_c_new_mapping(PRES_C_MAPPING_IGNORE);
return;
}
/*
* XXX --- Logic stolen from return-value initialization code that used
* to be in `mu_state::mu_server_func'. I copied the logic in order to
* reduce the code changes due to the new `PRES_C_MAPPING_PARAM_ROOT'
* scheme. But really, this logic is incomplete. We should either
* steal the more complete logic from `cast_new_expr_assign_to_zero',
* or we should bag initialization altogther.
*
* XXX --- Another problem: the PG is oblivious to any transformations
* that the BE may apply to the return type. So initializing the
* return value is suspect in any case.
*/
/*
* XXX --- If the return type is integer-like or a pointer,
* initialize `_return' to zero. Until we get real error
* handling this is better than nothing.
*/
zero_cexpr = 0;
switch (actual_ctype->kind) {
case CAST_TYPE_PRIMITIVE:
switch (actual_ctype->cast_type_u_u.primitive_type.kind) {
case CAST_PRIM_CHAR:
zero_cexpr = cast_new_expr_lit_char(0, 0);
break;
case CAST_PRIM_INT:
zero_cexpr = cast_new_expr_lit_int(0, 0);
break;
case CAST_PRIM_FLOAT:
zero_cexpr = cast_new_expr_lit_float(0.0);
break;
case CAST_PRIM_DOUBLE:
zero_cexpr = cast_new_expr_lit_double(0.0, 0);
break;
default:
panic("In `pg_state::p_server_func_alloc_return', "
"unrecognized CAST primitive type.");
break;
}
break;
case CAST_TYPE_POINTER:
zero_cexpr = cast_new_expr_lit_int(0, 0);
break;
default:
/* Do not initialize the return value. */
break;
}
/* Make the basic mapping: initialize the value or do nothing. */
if (zero_cexpr) {
*out_mapping = pres_c_new_mapping(PRES_C_MAPPING_INITIALIZE);
(*out_mapping)->pres_c_mapping_u_u.initialize.value
= zero_cexpr;
} else {
*out_mapping = pres_c_new_mapping(PRES_C_MAPPING_IGNORE);
}
/* Tell the back end that this is the ``root'' of the parameter. */
pres_c_interpose_param_root(out_mapping, 0, 0);
/* Tell the back end that this is a return parameter. */
pres_c_interpose_direction(out_mapping, AOI_DIR_RET);
}
/*
* This function digs through MINT to find the MINT references that we need in
* order to make a server work function.
*
* XXX --- The technique for finding these things is gross; we ought to have
* these MINT references *handed* to us.
*/
void pg_state::p_server_func_find_refs(aoi_interface *a,
aoi_operation * /*ao*/,
mint_const oper_request_discrim,
mint_const oper_reply_discrim,
/* OUT */ mint_ref *request_ref,
/* OUT */ mint_ref *reply_ref)
{
mint_ref interface_ref;
mint_const interface_discrim;
u_int number_of_interfaces;
u_int i;
/* `interface_ref' starts at the top level MINT union. */
interface_ref = top_union;
/*
* Descend past the IDL type union.
* XXX --- This is assuming only one case at the 'IDL type' union.
*/
interface_ref = m(interface_ref).mint_def_u.union_def.cases.
cases_val->var;
/* Now we need to find the current interface value. */
interface_discrim = mint_new_const_from_aoi_const(a->code);
number_of_interfaces = m(interface_ref).mint_def_u.union_def.
cases.cases_len;
for (i = 0; i < number_of_interfaces; ++i) {
if (!mint_const_cmp(interface_discrim,
(m(interface_ref).mint_def_u.union_def.
cases.cases_val[i].val))) {
interface_ref = m(interface_ref).mint_def_u.
union_def.cases.cases_val[i].var;
break;
}
}
if (i >= number_of_interfaces)
panic("In `pg_state::p_server_func_find_refs', "
"can't find interface MINT type.");
/*
* Once we've found the interface, finding the request and reply types
* is easy.
*/
*request_ref = mint_find_union_case(&(out_pres->mint), interface_ref,
oper_request_discrim);
*reply_ref = mint_find_union_case(&(out_pres->mint), interface_ref,
oper_reply_discrim);
if (*request_ref == mint_ref_null)
panic("In `pg_state::p_server_func_find_refs', "
" can't find operation request MINT type.");
if (*reply_ref == mint_ref_null)
panic("In `pg_state::p_server_func_find_refs', "
" can't find operation reply MINT type.");
}
/* End of file. */
syntax highlighted by Code2HTML, v. 0.9.1