/*
* Copyright (c) 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 <string.h>
#include <mom/compiler.h>
#include <mom/libmint.h>
#include <mom/c/libcast.h>
#include <mom/c/libpres_c.h>
#include "fluke.h"
/*
* Initialize the static member constant `fluke_mu_state::gather_allocator',
* which is used here. ANSI C++ doesn't let us initialize this static constant
* member in the class declaration --- blech!
*/
const char * const fluke_mu_state::gather_allocator = "fdev";
/*
* The Fluke version of `mu_array' recognizes and exploits opportunities for
* ``scatter/gather'' opimizations.
*
* XXX --- The current Fluke BE and runtime don't support scatter at all.
*
* XXX --- There are three problems with the current gather implementation that
* prevent us from doing gather in the general case:
*
* 1. The gathered objects must be the last objects marshaled in the message.
* If normal data is marshaled after gathered data, the effect is that the
* normal data will appear in the received message before the gathered
* data --- i.e., the marshaled data arrives out of order.
*
* 2. Fluke IPC requires that some minimum number of words be marshaled into
* the principal message buffer --- so not everything in the message can
* be gathered.
*
* 3. When the server gathers data for the reply, it must arrange for the
* gather buffers to be freed after the reply has been sent. This is can
* be handled through the MOM infrastructure's `cleanup' facility.
* However, the current implementation of ``gather'' doesn't record the
* functions required to free each individual gather buffer.
*
* Due to these limitations, the gather optimization is currently applied only
* to objects using a particular magic allocator named in `gather_allocator'.
* The magic allocator is bestowed by the Fluke PG on objects of certain types.
* Issue (1) is "solved" through users' knowledge. Issue (2) is "solved"
* because the magic allocator is applied only to sequences, and any message
* encoding a sequence will have at least the minimum number of words encoded
* in the main message buffer (the request/reply code and the sequence length).
* Issue (3) is "solved" because gathering is done only on objects using a
* particular allocator --- so the runtime can know what deallocator to call to
* free the gathered buffers.
*/
void fluke_mu_state::mu_array(
cast_expr array_expr, cast_type array_ctype,
cast_type elem_ctype, mint_ref elem_itype, pres_c_mapping elem_map,
char *cname)
{
cast_expr sizeof_expr;
int elem_size, elem_align_bits;
cast_stmt if_xlate_stmt;
int always_gather_p;
/*
* `sizeof_expr' will be non-null only if the array elements are
* `bcopy'able, ignoring endianness conversion (handled later on).
*/
sizeof_expr = mu_get_sizeof(elem_itype, elem_ctype, elem_map,
&elem_size, &elem_align_bits);
/*
* Determine if we can gather the array data. If not, we'll process it
* normally.
*/
mu_inline_alloc_context *iac = inline_alloc_context;
while (iac) {
if (strcmp(iac->name, cname) == 0)
break;
iac = iac->parent_context;
}
assert(iac);
pres_c_allocator allocer = get_allocator_kind(iac->alloc);
if (/* We're not using the magic allocator... */
!((allocer.kind == PRES_C_ALLOCATOR_NAME)
&& (strcmp(allocer.pres_c_allocator_u.name,
gather_allocator) == 0))
/* ...or we're not marshaling... */
|| !(op & MUST_ENCODE)
/* ...or the object isn't `bcopy'able. */
|| !sizeof_expr
) {
mem_mu_state::mu_array(array_expr, array_ctype,
elem_ctype, elem_itype, elem_map,
cname);
return;
}
/* We need the length expression, so grab it from the arglist. */
cast_expr len_expr;
cast_type len_type;
int gotarg = arglist->getargs(cname, "length", &len_expr, &len_type);
assert(gotarg);
assert(len_expr);
assert(len_type);
cast_stmt gather_if = 0, gather_else = 0, gather_endif = 0;
struct mu_abort_block *mab_par, *mab_con = 0, *mab_thr = 0;
/*
* Emit the array marshaling code. First, get the `#if' preprocessor
* statement that determines if we must perform endianness conversion
* on the data.
*/
if_xlate_stmt = mu_bit_translation_necessary(0 /* `#if' */,
elem_itype);
gather_if = if_xlate_stmt;
always_gather_p = (if_xlate_stmt->kind == CAST_STMT_TEXT)
&& (strncmp(if_xlate_stmt->cast_stmt_u_u.text,
"#if 0",
(sizeof("#if 0") - 1))
== 0);
mab_par = abort_block;
if (!always_gather_p) {
gather_else = mu_bit_translation_necessary(1, elem_itype);
gather_endif = mu_bit_translation_necessary(2, elem_itype);
/*
* There is a compile-time possibility that we won't be able to
* gather the data due to endianness conversion. So emit the
* normal marshaling code, too.
*
* XXX --- This code is untested because the Fluke BE always
* uses native endian encoding. Am I overlooking some glob/
* chunk management issues here?
*/
add_stmt(if_xlate_stmt);
/* We need to create a child abort block here to handle
the #if/#else/#endif stuff. */
mab_con = new mu_abort_block();
mab_con->set_kind(MABK_CONTROL);
mab_con->begin();
mab_con->add_stmt(gather_if);
mab_thr = new mu_abort_block();
mab_thr->set_kind(MABK_THREAD);
mab_thr->begin();
abort_block = mab_thr;
mem_mu_state::mu_array(array_expr, array_ctype,
elem_ctype, elem_itype, elem_map,
cname);
mab_thr->end();
mab_con->add_child(mab_thr, MABF_INLINE);
mab_con->add_stmt(gather_else);
mab_thr = new mu_abort_block();
mab_thr->set_kind(MABK_THREAD);
mab_thr->begin();
abort_block = mab_thr;
add_stmt(gather_else);
}
/*
* Bounds check the array, but only for *real* arrays.
* Normally, this is taken care of by the standard mu_array(), but
* we aren't running that here.
*/
if (array_data.is_valid)
mu_array_check_bounds(cname);
/* Construct and emit the call to the gathering macro. */
add_stmt(cast_new_stmt_expr(
cast_new_expr_call_3(
cast_new_expr_name(flick_asprintf("flick_%s_%s_gather",
get_be_name(),
get_buf_name())),
array_expr,
cast_new_binary_expr(CAST_BINARY_MUL,
len_expr,
cast_new_expr_lit_int(elem_size,
0)),
cast_new_expr_name(abort_block->use_current_label())
)
));
/*
* Terminate the array, but only for *real* arrays.
* Normally, this is taken care of by the standard mu_array(), but
* we aren't running that here.
*/
if (array_data.is_valid)
mu_array_terminate(array_expr, elem_ctype, cname);
if (!always_gather_p) {
add_stmt(gather_endif);
mab_thr->end();
mab_con->add_child(mab_thr, MABF_INLINE);
mab_con->add_stmt(gather_endif);
mab_con->end();
mab_par->add_child(mab_con, MABF_INLINE);
abort_block = mab_par;
}
}
/*
* For Fluke strings, we encode the terminator as part of the string.
*/
int fluke_mu_state::mu_array_encode_terminator(char *cname)
{
return mu_array_is_string(cname);
}
/* End of file. */
syntax highlighted by Code2HTML, v. 0.9.1