/*
* 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/libmint.h>
#include <mom/c/libcast.h>
#include <mom/c/libpres_c.h>
#include <mom/c/pbe.hh>
/*****************************************************************************/
/* This functor is called by `mu_union_case' to generate the code that will be
executed when an optional datum is present. This code marshals/unmarshals
the datum. */
struct mu_mapping_optional_pointer_then_functor : public functor
{
virtual void func(mu_state *must);
mu_mapping_optional_pointer_then_functor() {}
/*****/
mint_array_def *adef;
cast_expr len_var_expr;
cast_expr ptr_expr;
cast_type ptr_ctype;
pres_c_mapping_optional_pointer *ptr_map;
};
void mu_mapping_optional_pointer_then_functor::func(mu_state *must)
{
/* Find the type of the pointer target. */
assert(ptr_ctype->kind == CAST_TYPE_POINTER);
cast_type target_ctype = ptr_ctype->cast_type_u_u.pointer_type.target;
/* Allocate space */
assert(ptr_ctype->kind == CAST_TYPE_POINTER);
must->mu_pointer_alloc(ptr_expr, target_ctype, ptr_map->arglist_name);
must->mu_mapping(cast_new_unary_expr(CAST_UNARY_DEREF, ptr_expr),
target_ctype, adef->element_type, ptr_map->target);
/* Deallocate space */
assert(ptr_ctype->kind == CAST_TYPE_POINTER);
must->mu_pointer_free(ptr_expr, target_ctype, ptr_map->arglist_name);
}
/*****************************************************************************/
/* This functor is called by `mu_union_case' in order to generate the code
to be executed when the optional data is not present. When marshaling,
there is nothing to do (the zero "count" has already been marshaled). When
unmarshaling, however, we must set the CAST pointer to NULL. */
struct mu_mapping_optional_pointer_else_functor : public functor
{
virtual void func(mu_state *must);
mu_mapping_optional_pointer_else_functor() {}
/*****/
cast_expr ptr_expr;
};
void mu_mapping_optional_pointer_else_functor::func(mu_state *must)
{
if (must->op & MUST_DECODE)
must->add_stmt(cast_new_stmt_expr(cast_new_expr_assign(
ptr_expr,
cast_new_expr_lit_int(0, 0)
)));
must->break_chunk();
}
/*****************************************************************************/
/* This functor is called by `mu_union' in order to generate the code that
marshals/unmarshals the "variants" of an optional pointer --- i.e., the
optional datum if present, or nothing. The "discriminator" of the optional
pointer is handled separately, by `mu_mapping_optional_pointer', before this
functor is invoked. */
struct mu_mapping_optional_pointer_functor : public functor
{
virtual void func(mu_state *must);
mu_mapping_optional_pointer_functor() {}
/*****/
cast_expr len_var_expr;
mu_mapping_optional_pointer_then_functor then_functor;
mu_mapping_optional_pointer_else_functor else_functor;
};
/* This method produces the C `if' statement that processes the "variants" of
the optional pointer.
*/
void mu_mapping_optional_pointer_functor::func(mu_state *must)
{
mu_memory_allocator_state *initial_memory_state;
cast_stmt saved_block, then_block, else_block;
mu_msg_span *union_span = 0, *parent_span = 0;
char *skip_label = must->add_label();
/* At this point we want to generate an `if' statement:
`if (<len_var_expr>) { ... } else { ... };'
Unfortunately, most of the functions that generate code don't
*return* code --- instead, they call `add_stmt()' to append code to
the current block. Because we need the code generated by the
following function calls to go into blocks within an `if', we must
save the current value of `must->c_block', call the functions, and
then fix up the code. Ugh.
Moreover, because we're generating a code branch, we must remember
the initial state of the glob/chunk memory allocator so that we can
restore it before generating each branch.
*/
/* Prepare to generate the `if' statement: Take a snapshot of the
current memory allocator, and save off the current `c_block'. */
initial_memory_state = must->memory_allocator_state();
saved_block = must->c_block;
/* An optional pointer adds an 'if' so we need to replicate this
in the abort code. */
struct mu_abort_block *mab_par, *mab_con, *mab_thr;
mab_par = must->abort_block;
mab_con = new mu_abort_block();
mab_con->set_kind(MABK_CONTROL_IF_ELSE);
mab_con->begin();
mab_con->add_stmt(cast_new_stmt_expr(cast_new_expr_assign(
len_var_expr,
cast_new_binary_expr(CAST_BINARY_NE,
else_functor.ptr_expr,
cast_new_expr_lit_int(0, 0)))));
/* A variable length message means we need to
add a span for each case. */
if( must->current_span ) {
union_span = new mu_msg_span;
union_span->set_kind(MSK_UNION);
union_span->set_block(must->c_block);
union_span->set_abort(must->abort_block);
union_span->begin();
parent_span = must->current_span;
must->current_span = new mu_msg_span;
must->current_span->set_kind(MSK_SEQUENTIAL);
must->current_span->set_block(must->c_block);
must->current_span->set_abort(must->abort_block);
must->current_span->begin();
}
mab_thr = new mu_abort_block();
must->abort_block = mab_thr;
mab_thr->set_kind(MABK_THREAD);
mab_thr->set_expr(len_var_expr);
mab_thr->begin();
/* Generate and collect the code for the `then' arm. */
must->c_block = cast_new_block(0, 0);
must->mu_union_case(&then_functor);
then_block = must->c_block;
/* Since there is no way to break out of an if statement
like a loop or switch, we have to manually do a goto. */
must->add_stmt(cast_new_goto(skip_label));
mab_thr->end();
mab_con->add_child(mab_thr, MABF_OUT_OF_LINE);
must->add_stmt(mab_thr->get_block_label());
if( parent_span ) {
must->current_span->end();
union_span->add_child(must->current_span);
}
/* Handle span and abort stuff for the else case */
mab_thr = new mu_abort_block();
must->abort_block = mab_thr;
mab_thr->set_kind(MABK_THREAD);
mab_thr->set_expr(0);
mab_thr->begin();
if( parent_span ) {
must->current_span = new mu_msg_span;
must->current_span->set_kind(MSK_SEQUENTIAL);
must->current_span->set_block(must->c_block);
must->current_span->set_abort(must->abort_block);
must->current_span->begin();
}
/* Generate and collect the code for the `else' arm. */
must->c_block = cast_new_block(0, 0);
must->set_memory_allocator_state(initial_memory_state);
must->mu_union_case(&else_functor);
else_block = must->c_block;
must->add_stmt(cast_new_goto(skip_label));
mab_thr->end();
mab_con->add_child(mab_thr, MABF_OUT_OF_LINE);
must->add_stmt(mab_thr->get_block_label());
if( parent_span ) {
must->current_span->end();
union_span->add_child(must->current_span);
union_span->end();
parent_span->add_child(union_span);
must->current_span = parent_span;
}
must->abort_block = mab_par;
mab_con->end();
mab_par->add_child(mab_con, MABF_OUT_OF_LINE);
/* Finally, output the `if'. */
must->c_block = saved_block;
must->add_stmt(cast_new_if(len_var_expr, then_block, else_block));
/* During a normal run we need to jump past the abort code inside
of the if/then and to the next part of the regular code. */
cast_stmt clabel;
must->add_stmt(mab_con->get_block_label());
clabel = cast_new_label(skip_label, cast_new_stmt(CAST_STMT_NULL));
clabel->cast_stmt_u_u.s_label.users = 2;
must->add_stmt(clabel);
}
/*****************************************************************************/
/* `mu_state::mu_optional_pointer_mapping' is the method that handles the
PRES_C_MAPPING_OPTIONAL_POINTER mapping.
This mapping embodies the following presentation semantics: An optional
datum is present if a certain C pointer points to it. If the optional datum
is not present, the C pointer is null. In MINT, an optional pointer
corresponds to a counted array with zero or one elements.
On encoding, the given C pointer is examined. If it is null, a counted
array with zero elements is marshaled into our message. If the pointer is
non-null, a counted array with one element is marshaled. The single element
is the datum that the pointer points at.
On decoding, the counted array in the message is examined. If it contains
zero elements, the C pointer is set to null. Otherwise, the first element
of the array is unmarshaled, and the C pointer is set to point to it.
A `pres_c_mapping_optional_pointer' is unlike a `pres_c_mapping_pointer' in
that an optional pointer doesn't just "eat up" one level of C pointer
indirection. An optional pointer is a presentation mechanism that embodies
semantics --- the value of the pointer (NULL or non-NULL) is determined by
the presence of the optional datum. A simple `pres_c_mapping_pointer', on
the other hand, doesn't have any semantics to speak of --- it's simply a way
of presenting data.
*/
void mu_state::mu_mapping_optional_pointer(
cast_expr ptr_expr,
cast_type ptr_ctype,
mint_ref itype,
pres_c_mapping_optional_pointer *ptr_map)
{
mu_mapping_optional_pointer_functor f;
assert(itype >= 0);
assert(itype < (signed int) pres->mint.defs.defs_len);
mu_array_data old_array_data = array_data;
mint_def *def = &pres->mint.defs.defs_val[itype];
assert(def->kind == MINT_ARRAY);
mint_array_def *adef = &def->mint_def_u.array_def;
mint_get_array_len(&pres->mint, itype,
&array_data.mint_len_min,
&array_data.mint_len_max);
array_data.is_valid = 1;
mu_inline_alloc_context *iac = inline_alloc_context;
while (iac) {
if (strcmp(iac->name, ptr_map->arglist_name) == 0)
break;
iac = iac->parent_context;
}
if (!iac)
panic(("In `mu_state::mu_mapping_optional_pointer', "
"allocation context `%s' not available."),
ptr_map->arglist_name);
/* Create a temporary variable in which to hold the array length. */
cast_expr len_expr;
cast_type len_ctype;
int gotarg = arglist->getargs(ptr_map->arglist_name,
"length", &len_expr, &len_ctype);
assert(gotarg);
assert(len_expr);
assert(len_ctype);
/* Break the current chunk. Since the next datum is optional, its size
is variable (zero or non-zero), and therefore we can't possibly
continue the current chunk. */
break_chunk();
/* Finally, fill out the functor that will generate our `if' statement,
and give that functor to `mu_union'. `mu_union' will do glob/chunk
management around our `if', and `mu_union_case' will do glob/chunk
management for each arm of our `if'. */
f.len_var_expr = len_expr;
f.then_functor.adef = adef;
f.then_functor.len_var_expr = len_expr;
f.then_functor.ptr_expr = ptr_expr;
f.then_functor.ptr_ctype = ptr_ctype;
f.then_functor.ptr_map = ptr_map;
f.else_functor.ptr_expr = ptr_expr;
mu_union(&f);
/* Restore the array data. */
array_data = old_array_data;
}
/* End of file. */
syntax highlighted by Code2HTML, v. 0.9.1