/* * Copyright (c) 1995, 1996, 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. */ /* These methods override the default do_nothing versions in mu_state, providing typically appropriate behavior when marshaling unions to/from memory-based marshaling streams. This code assumes that unions are handled by first marshaling the union discriminator, and then marshaling the union branch it selects. Only the amount of message space needed by the selected union branch is reserved - i.e. a marshaled union is generally variable-length. This contrasts with C unions, in which unions always occupy the amount of memory needed to hold the largest branch of the union. We use the variable `union_end_align' in the parent mu_state to calculate the minimum alignment of the union as a whole. This is the minimum of the final alignments of each possible branch. For example, if each branch in the union ends with an `int' aligned at a 4-byte boundary, then no matter which branch is taken at run time, we know the message stream will be 4-byte aligned after the full union is marshaled. If the next item we marshal after the union needs 4-byte alignment or less, we don't have to produce any run-time alignment checking code for it. However, if one of the union branches ends with a variable-length array of chars, then no particular alignment is guaranteed, and a run-time alignment check might be needed. */ #include #include void mem_mu_state::mu_union_case(functor *f) { if (!union_one_glob) { // The following assertions are not always true now that union // processing code is created by `mu_discriminate' and // `hash_const::hash'. In particular, `mu_union' is called // *before* we marshal/unmarshal the discriminator, which means // that we will have a glob at this point. // // assert(glob_size_expr == 0); // assert(glob_size == 0); } else { // The following assertion is also no longer true, because // marshaling/unmarshaling the union discriminator may leave us // without a glob. (This occurs most commonly when the // discriminator is handled by a marshal/unmarshal stub.) // // assert(glob_size_expr != 0); // // However, we do know this: if (glob_size_expr == 0) /* `mem_mu_union' makes sure that there is a glob to begin with. If it's already gone, then that means that m/u'ing the discriminator broke the glob. */ union_one_glob = 0; // Really, all code that invokes `mu_union' and `mu_union_case' // should be fixed so that it never calls `mu_union' before the // discriminator has been processed. That way, if the // processing of the discriminator breaks the glob, we can // still recover and make a new single glob for the cases. // // I believe that the above suggestion has been implemented, // *except* within `mu_discriminate'. } /* We used to save the glob size and alignment info here, but mem_mu_union saves the mem_state at the start of the union. */ cast_expr *init_glob_size_expr = glob_size_expr; /* Perform the actual union case processing. */ mu_state::mu_union_case(f); /* Finish off the case's last chunk, if any. */ break_chunk(); /* Adjust the union's overall final alignment to be the least common denominator of all the possible cases. */ if (union_align_bits < 0) { union_align_bits = align_bits; union_align_ofs = align_ofs; assert(union_align_ofs < (1 << union_align_bits)); } else { if (align_bits < union_align_bits) union_align_bits = align_bits; while ((union_align_ofs ^ align_ofs) & ((1 << union_align_bits)-1)) union_align_bits--; union_align_ofs &= (1 << union_align_bits) - 1; } /* See if we're in our dry run and are failing the one-glob test. */ if (union_one_glob && (glob_size_expr != init_glob_size_expr)) { // As explained above, the following assertion is no longer // always true now that union-processing code is generated by // `mu_discriminate'. Although `union_one_glob' may still be // true, we may not have started off with no glob at all. // // assert(init_glob_size == 0); union_one_glob = 0; } /* Accumulate the maximum possible final glob_size in union_glob_size. */ if (union_one_glob) { if (glob_size > union_glob_size) union_glob_size = glob_size; } else { /* We break the glob here in order to ensure that every union case leads to a glob/chunk state that is consistent with the states produced by all the other union cases. Currently, we ensure consistency by forcing every case to result in a state in which there is no current glob. */ break_glob(); assert(glob_size_expr == 0); assert(glob_size == 0); } /* Accumulate the maximum possible final msg_size in union_msg_size. */ if (max_msg_size > union_msg_size) union_msg_size = max_msg_size; }