/* * 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 #include #include #include #include #include #include #include #include "private.hh" /*****************************************************************************/ void pg_state::p_client_stubs(aoi_interface * /*ai*/) { p_client_stubs_internal(cur_aoi_idx, cur_aoi_idx); } void pg_state::p_client_stubs_internal(aoi_ref this_ref, aoi_ref derived_ref) { aoi_interface *this_interface, *derived_interface; aoi_ref saved_parent_ref, saved_derived_ref; u_int ops_len; #ifdef ATTRIBUTE_STUBS u_int attribs_len; #endif u_int parents_len; u_int i; int flags; /* * Set `this_interface' and `derived_interface' to point at the AOI * interfaces under consideration. */ assert((this_ref >= 0) && (this_ref < ((aoi_ref) in_aoi->defs.defs_len))); assert(a(this_ref).binding && (a(this_ref).binding->kind == AOI_INTERFACE)); this_interface = &(a(this_ref).binding->aoi_type_u_u.interface_def); assert((derived_ref >= 0) && (derived_ref < ((aoi_ref) in_aoi->defs.defs_len))); assert(a(derived_ref).binding && (a(derived_ref).binding->kind == AOI_INTERFACE)); derived_interface = &(a(derived_ref).binding->aoi_type_u_u. interface_def); /* * Set the `pg_state' interface reference data members to point at the * interfaces under consideration so that `pg_state::calc_name' can * compute names. */ saved_parent_ref = parent_interface_ref; saved_derived_ref = derived_interface_ref; parent_interface_ref = this_ref; derived_interface_ref = derived_ref; /* Get the lengths of arrays that are part of `this_interface'. */ ops_len = this_interface->ops.ops_len; #ifdef ATTRIBUTE_STUBS attribs_len = this_interface->attribs.attribs_len; #endif parents_len = this_interface->parents.parents_len; /* Generate the send message function for asynchronous messages. */ if (async_stubs && derived_interface == this_interface) { p_send_stub(derived_interface, 1 /* request */); p_send_stub(derived_interface, 0 /* reply */); p_continue_func_types(derived_interface); } /* * Generate the stubs for the operations defined by `this_interface', * which are inherited by `derived_interface'. */ for (i = 0; i < ops_len; ++i) { aoi_operation *ao = &(this_interface->ops.ops_val[i]); /* * We must check if we have already generated a stub for this * (interface, operation) pair. This may occur, for example, * when `this_interface' is inherited through multiple paths * to `derived_interface'. */ flags = p_interface_table_get_value(derived_interface, ao); if (!(flags & P_CLIENT_STUB_OP_MARK)) { p_interface_table_set_value(derived_interface, ao, (flags | P_CLIENT_STUB_OP_MARK)); if (async_stubs) { p_message_marshal_stub(derived_interface, ao, 1 /* client */, 1 /* request */); p_message_marshal_stub(derived_interface, ao, 1 /* client */, 0 /* reply */); p_receive_func(derived_interface, ao, 0 /* reply */); p_continue_stub(derived_interface, ao, 0 /* reply */); } else p_client_stub(derived_interface, ao); } } #ifdef ATTRIBUTE_STUBS /* * Generate the stubs for the attributes defined by `this_interface', * which are inherited by `derived_interface'. */ for (i = 0; i < attribs_len; ++i) { aoi_attribute *aa = &(this_interface->attribs.attribs_val[i]); /* * As above, we must screen out attributes that we have already * processed. */ flags = p_interface_table_get_value(derived_interface, aa); if (!(flags & P_CLIENT_STUB_OP_MARK)) { p_interface_table_set_value(derived_interface, aa, (flags | P_CLIENT_STUB_OP_MARK)); p_client_attrib_stub(derived_interface, aa); } } #endif /* ATTRIBUTE_STUBS */ /* * Generate the stubs for the operations and attributes that are * inherited from parents of `this_interface'. */ for (i = 0; i < parents_len; ++i) { aoi_type parent_val = this_interface->parents.parents_val[i]; aoi_ref parent_ref; aoi_interface *parent_interface; /* * All parent references must be through indirects so that * we can find the name to go with the parent interface! */ assert(parent_val->kind == AOI_INDIRECT); parent_ref = aoi_deref_fwd(in_aoi, parent_val->aoi_type_u_u.indirect_ref); parent_interface = &(a(parent_ref).binding->aoi_type_u_u. interface_def); /* * As above, we check to see if we've already processed this * parent. (If we didn't do this check we would still generate * correct code because all of the parent's operations and * attributes are marked separately. But doing this check can * save us time.) */ flags = p_interface_table_get_value(derived_interface, parent_interface); if (!(flags & P_CLIENT_STUB_PARENT_MARK)) { p_interface_table_set_value( derived_interface, parent_interface, (flags | P_CLIENT_STUB_PARENT_MARK)); p_client_stubs_internal(parent_ref, derived_ref); } } /* * Finally, restore the `pg_state' AOI interface references that we * changed previously. */ parent_interface_ref = saved_parent_ref; derived_interface_ref = saved_derived_ref; } /*****************************************************************************/ /* * Generate a client stub presentation for an AOI interface operation. * * Note that `ao' may not be defined in `ai', but rather in some parent * interface of `ai'. */ void pg_state::p_client_stub(aoi_interface *ai, aoi_operation *ao) { pres_c_client_stub *cstub; int newstub; char *old_name; char *opname; int cast_params_len; int cr, 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; cast_scope *scope = (cast_scope *)top_ptr(scope_stack); /*****/ /* * Some presentation styles dictate that client stubs are created only * for operations that are *defined* within an interface, not for * operations that are *inherited* from parent interfaces. In such a * presentation, one would invoke the parent's client stub to invoke an * inherited operation on an instance of a derived object type. */ if ((parent_interface_ref != derived_interface_ref) && !client_stubs_for_inherited_operations) return; if(!lookup_interface_mint_discrims(ai, ao, &oper_request, &oper_reply)) { panic("In `pg_state::p_client_stub', " "cannot find MINT request and reply discriminators."); } /* * Find the MINT references to the request and reply types. */ p_client_stub_find_refs(ai, ao, oper_request, oper_reply, &request_ref, &reply_ref); /* * Determine the special parameters for this stub: the target object * reference, the environment reference, etc. */ p_client_stub_special_params(ao, &specials); /* * Determine the total number of stub 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_client_stub_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_type_mapping; cast_type out_ctype_temp; process_client_params(&cfunc, &specials, request_ref, reply_ref, ao, request_l4_inl, reply_l4_inl, target_inl, 0 /* no client inline */); /* * 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_client_stub_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]), &out_ctype_temp, &return_type_mapping); cfunc.return_type = out_ctype_temp; /* * Allocate a pres_c_stub for this operation --- UNLESS we have already * created an appropriate client stub. * * Perhaps we are inheriting the current AOI operation from a parent * interface and the user has changed the rule for creating stub names * so that we now have a name conflict. (In this case, however, the * user should instead tweak the flag that controls the creation of * client stubs for inherited operations.) * * XXX --- We should be more careful about this check. Checking just * the name is bad news. We must check for MINT and PRES_C equality as * well! */ cast_scope *deep_scope = scope; if (!(ao->flags & (AOI_OP_FLAG_SETTER|AOI_OP_FLAG_GETTER)) && (cast_find_def(&deep_scope, cast_new_scoped_name(name, NULL), CAST_FUNC_DECL) >= 0)) { /* * XXX --- Check that our MINT and PRES_C is equal to that of * the existing client stub. (Hell, check that `name' refers * to a client stub and not some typedef or something else!) * * In lieu of being smart, warn the user. */ warn("Suppressing extra definition for client stub `%s'.", name); /* Restore the name context. */ name = old_name; return; } newstub = p_add_stub(out_pres); s(newstub).kind = PRES_C_CLIENT_STUB; cstub = &s(newstub).pres_c_stub_u.cstub; cstub->op_flags = PRES_C_STUB_OP_FLAG_NONE; /* Determine if the operation is oneway. */ if (ao->flags & AOI_OP_FLAG_ONEWAY) cstub->op_flags |= PRES_C_STUB_OP_FLAG_ONEWAY; /* * Set request_itype and reply_itype to the top-level "mom_msg" MINT * union. */ cstub->request_itype = top_union; cstub->reply_itype = top_union; cfunc.spec = client_func_spec; deep_scope = scope; cast_scoped_name scn = cast_new_scoped_name(opname, NULL); if( ((ao->flags & (AOI_OP_FLAG_SETTER|AOI_OP_FLAG_GETTER)) || (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_CLIENT_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 = client_func_spec; } cfunc.spec &= ~CAST_FUNC_VIRTUAL; cdef = cast_add_def(&out_pres->stubs_cast, calc_client_stub_scoped_name(cur_aoi_idx, opname), CAST_SC_NONE, CAST_FUNC_DECL, ch(cur_aoi_idx, PG_CHANNEL_CLIENT_IMPL), current_protection); out_pres->stubs_cast.cast_scope_val[cdef]. u.cast_def_u_u.func_type = cfunc; cstub->c_func = cdef; /* * 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, initialize the request `return_slot' to null. */ 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_type_mapping); request_l4_inl->pres_c_inline_u_u.func_params_i.return_slot = 0; /* * We need to turn the reply into the union of good, bad, & ugly values */ p_do_return_union(ao, &reply_l4_inl, reply_ref, cr, 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 cstub fields. */ cstub->request_i = request_l1_inl; cstub->reply_i = reply_l1_inl; /* Set the target_i field. */ cstub->target_i = target_inl; cstub->target_itype = out_pres->mint.standard_refs.interface_name_ref; /* Set the client_i field. */ cstub->client_i = 0; cstub->client_itype = mint_ref_null; /* Set the error_i field. */ /* XXX until exception handling is implemented */ cstub->error_i = reply_l1_inl; cstub->error_itype = top_union; /* Restore the name context. */ name = old_name; } /*****************************************************************************/ /***** Auxiliary functions. *****/ void pg_state::p_client_stub_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_client_stub_object_param_name(ao->name); this_param->ctype = cast_new_type_name( calc_client_stub_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_client_stub_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_client_stub_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_client_stub_client_sid_param_name(ao->name); this_param->ctype = cast_new_type_name( calc_client_stub_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_client_stub_required_server_sid_param_name(ao->name); this_param->ctype = cast_new_type_name( calc_client_stub_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 to appear after the required server SID if * `gen_sids' is true. Otherwise, the actual server SID does not * appear. */ this_param = &(specials->params[stub_special_params:: actual_server_sid]); this_param->name = calc_client_stub_actual_server_sid_param_name(ao->name); this_param->ctype = cast_new_type_name( calc_client_stub_server_sid_type_name(ao->name)); if (gen_sids) this_param->index = (ao->params.params_len + 3); else this_param->index = -1; /* Finally, we're done! */ } /* * This method determines how `p_client_stub' processes the return type of a * client stub. Some presentation generators override this method. */ void pg_state::p_client_stub_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 function digs through MINT to find the MINT references that we need in * order to make a client stub. * * XXX --- The technique for finding these things is gross; we ought to have * these MINT references *handed* to us. */ void pg_state::p_client_stub_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_client_stub_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_client_stub_find_refs', " " can't find operation request MINT type."); if (*reply_ref == mint_ref_null) panic("In `pg_state::p_client_stub_find_refs', " " can't find operation reply MINT type."); } /* End of file. */