diff options
Diffstat (limited to 'TAO/tao/interp.cpp')
-rw-r--r-- | TAO/tao/interp.cpp | 1504 |
1 files changed, 0 insertions, 1504 deletions
diff --git a/TAO/tao/interp.cpp b/TAO/tao/interp.cpp deleted file mode 100644 index e1d25b20a01..00000000000 --- a/TAO/tao/interp.cpp +++ /dev/null @@ -1,1504 +0,0 @@ -// @(#)interp.cpp 1.4 95/11/04 -// Copyright 1994-1995 by Sun Microsystems Inc. -// All Rights Reserved -// -// TYPECODE: interpreter, traverses data structures -// -// This uses the standard C/C++ representation for data, and knows how -// to do things like align and pad according to standard rules. It is -// driven by CDR marshaled representations of TypeCodes. -// -// It does two key things: (a) calculate size and alignment -// restrictions for the data type described by any given typecode; and -// (b) "visits" each element of a data type in the order those -// elements are defined in the type's IDL definition. -// -// A typical use is that some application-specific "visit" function -// will be called with a typecode and data value. Then that "visit" -// function may choose to use the interpreter's knowledge of the -// environment's size, padding, and alignment rules to help it examine -// each of the constituents of complex data values. It does so by -// making a call to TypeCode::traverse(), and passing itself for -// future recursive calls. -// -// NOTE that this module has system dependent parts, and so should be -// examined when porting to new CPU architectures, compilers, and so -// forth to make sure it correctly implements the appropriate binary -// interfaces. -// -// Issues of concern are primarily that sizes and representations of -// CORBA primitive data types are correct (key issues are verified -// when the ORB initializes) and that the alignment rules are -// recognized. -// -// Also, exceptions have vtables in them, which may cause trouble if -// they aren't located at the very beginning by the compiler in -// question. -// -// So for example, moving to another CPU architecture which still uses -// standard sized two's complement integers and IEEE floating point, -// and expects "natural" alignment, won't be hard. Even using PC -// style tightly packed data is simple; the alignment rules are just -// simpler. Most volume microprocessors used in 1995 are correctly -// supported. -// -// Using data representations that are far from the standard C/C++ -// style data layout is probably not practical with this -// implementation. LISP systems, as one example, probably won't use -// "in-memory" representations much like C/C++, even though its "wire -// form" could directly match CDR. -// -// ALSO, the treatment of exceptions may need to be examined in -// language environments which actually rely on C++ exceptions. The -// RTTI data that identifies exceptions can easily be ignored by this -// interpreter (if it's taught about that compiler's RTTI) but it may -// not be practical for any code not generated by that specific C++ -// compiler to store such data in the right place to look like a C++ -// exception, or to throw exceptions when that's needed. (RTTI == -// "Run Time Typing Information", needed to make C++ exceptions work -// correctly and partially exposed to users by the ANSI standards -// comittee. It provides type-safe "downcasting" and other features -// previously unavailable in C++.) -// -// THREADING NOTE: Data structures being traversed should only be -// modified by the thread doing the traversal. The interpretive code -// itself is reentrant (recursive!) so presents no threading issues; -// only the data being fed to the interpreter must be protected -// against concurrency. - -#include "tao/corba.h" - -// Utility routines are used to manipulate CDR-encapsulated TypeCode -// parameter lists, calculating the size and alignment of the data -// type being described. The TCKind value has always been removed -// from the CDR stream when these calculator routines get called. - -typedef size_t attribute_calculator (CDR *stream, - size_t &alignment, - CORBA::Environment &env); - -static attribute_calculator calc_struct_attributes; -static attribute_calculator calc_exception_attributes; -static attribute_calculator calc_union_attributes; -static attribute_calculator calc_alias_attributes; -static attribute_calculator calc_array_attributes; - -// Other utility routines are used to skip the parameter lists when -// they're not needed. - -typedef CORBA::Boolean param_skip_rtn (CDR *); - -static CORBA::Boolean -skip_encapsulation (CDR *stream) -{ - return stream->skip_string (); -} - -static CORBA::Boolean -skip_long (CDR *stream) -{ - CORBA::ULong scratch; - - return stream->get_ulong (scratch); -} - -// Table supporting calculation of size and alignment requirements for -// any one instance of a given data types. -// -// This is indexed via CDR's TCKind values, which are "frozen" as part -// of the CDR standard. Entries hold either the size and alignment -// values for that data type, or a pointer to a function that is used -// to calculate those values. Function pointers are normally needed -// only for constructed types. -// -// A "skipper" routine is provided for some data types whose size is -// known statically (e.g. objrefs, structures, strings) but whose -// typecodes have parameters that sometimes need to be ignored when -// found in a CDR stream. Any attribute calculator routine always -// skips parameters in the CDR input stream, so no type with such a -// routine also needs a "skipper". -// -// Rather than growing a set of processor-specific #ifdefs, we -// calculate most of this table (except functions) at ORB -// initialization time. - -struct table_element -{ - size_t size; - size_t alignment; - attribute_calculator *calc; - param_skip_rtn *skipper; -}; - -static table_element table [CORBA::TC_KIND_COUNT] = -{ - { 0, 1, 0 }, // CORBA::tk_null - { 0, 1, 0 }, // CORBA::tk_void - - { 0, 1, 0, 0 }, // CORBA::tk_short - { 0, 1, 0, 0 }, // CORBA::tk_long - { 0, 1, 0, 0 }, // CORBA::tk_ushort - { 0, 1, 0, 0 }, // CORBA::tk_ulong - - { 0, 1, 0, 0 }, // CORBA::tk_float - { 0, 1, 0, 0 }, // CORBA::tk_double - - { 0, 1, 0, 0 }, // CORBA::tk_boolean - { 0, 1, 0, 0 }, // CORBA::tk_char - { 0, 1, 0, 0 }, // CORBA::tk_octet - { 0, 1, 0, 0 }, // CORBA::tk_any - - { 0, 1, 0, 0 }, // CORBA::tk_TypeCode - { 0, 1, 0, 0 }, // CORBA::tk_Principal - { 0, 1, 0, skip_encapsulation }, // CORBA::tk_objref - - { 0, 1, calc_struct_attributes, 0 }, // CORBA::tk_struct - { 0, 1, calc_union_attributes, 0 }, // CORBA::tk_union - - { 0, 1, 0, skip_encapsulation }, // CORBA::tk_enum - { 0, 1, 0, skip_long }, // CORBA::tk_string - { 0, 1, 0, skip_encapsulation }, // CORBA::tk_sequence - { 0, 1, calc_array_attributes, 0 }, // CORBA::tk_array - - // - // Two TCKind values added in 94-11-7 - // - { 0, 1, calc_alias_attributes, 0 }, // CORBA::tk_alias - { 0, 1, calc_exception_attributes, 0 }, // CORBA::tk_except - - // - // Five extended IDL data types, defined in Appendix A of 94-9-32 - // but here with different numeric TCKind codes. These types - // represent extensions to CORBA (specifically, to IDL) which are - // not yet standardized. - // - { 0, 1, 0, 0 }, // CORBA::tk_longlong - { 0, 1, 0, 0 }, // CORBA::tk_ulonglong - { 0, 1, 0, 0 }, // CORBA::tk_longdouble - { 0, 1, 0, 0 }, // CORBA::tk_wchar - { 0, 1, 0, skip_long } // CORBA::tk_wstring -}; - -// Runtime initialization of the table above; note that this compiles -// down to a set of assignment statements, with the real work done by -// the C++ compiler when this file gets compiled. -// -// "Natural alignment" is a policy that the processor controls the -// alignment of data based on its type. There's variation; some CPUs -// have a maximum alignment requirement of two or four bytes, others -// have some type-specific exceptions to the normal "alignment == -// size" rule. -// -// "Fixed" alignment ignores data type when establishing alignment; -// not all processors support such policies, and those which do often -// pay a cost to do so (viz. RISC/CISC discussions). The primary -// example of an OS family that chose "fixed" alignment is Microsoft's -// x86 systems, which normally align on one byte boundaries to promote -// data space efficiency. -// -// NOTE: typical PC compiler options let you specify other alignments, -// but none are "natural". Also, they don't apply consistently to all -// data types. Change the "one byte" assumption with extreme caution! -// And make sure all header files (e.g. generated by an IDL compiler) -// make sure that alignment of IDL-defined data types is consistent -// (one byte). - - enum TCKIND - { - tk_null = 0, - tk_void = 1, - tk_short = 2, - tk_long = 3, - tk_ushort = 4, - tk_ulong = 5, - tk_float = 6, - tk_double = 7, - tk_boolean = 8, - tk_char = 9, - tk_octet = 10, - tk_any = 11, - tk_TypeCode = 12, - tk_Principal = 13, - tk_objref = 14, - tk_struct = 15, - tk_union = 16, - tk_enum = 17, - tk_string = 18, - tk_sequence = 19, - tk_array = 20, - tk_alias = 21, // 94-11-7 - tk_except = 22, // 94-11-7 - - // these five are OMG-IDL data type extensions - tk_longlong = 23, // 94-9-32 Appendix A (+ 2) - tk_ulonglong = 24, // 94-9-32 Appendix A (+ 2) - tk_longdouble = 25, // 94-9-32 Appendix A (+ 2) - tk_wchar = 26, // 94-9-32 Appendix A (+ 2) - tk_wstring = 27, // 94-9-32 Appendix A (+ 2) - - // This symbol is not defined by CORBA 2.0. It's used to speed up - // dispatch based on TCKind values, and lets many important ones - // just be table lookups. It must always be the last enum value!! - - TC_KIND_COUNT - }; - -#if defined (unix) || defined (VXWORKS) || defined (ACE_WIN32) -#define declare_entry(x,t) \ - struct align_struct_ ## t { \ - x one; \ - char dummy [TAO_ALIGNMENT_MAGIC_NUMBER + 1 - sizeof(x)]; \ - x two; \ - } - -#define setup_entry(x,t) \ - { \ - align_struct_ ## t align; \ - table [t].size = sizeof (x); \ - table [t].alignment = \ - (char *) &align.two - (char *) &align.one - TAO_ALIGNMENT_MAGIC_NUMBER; \ - } - -#else // "Fixed" byte alignment -// Have a bogus one -#define declare_entry(x,t) struct align_struct_ ## t { } -#define setup_entry(x,t) \ - { \ - table [t].size = sizeof (x); \ - table [t].alignment = 1; \ - } - -#endif /* defined (unix) || defined (VXWORKS) || defined (ACE_WIN32) */ - -// Fills in fixed size and alignment values. - -declare_entry (CORBA::Short, tk_short); -declare_entry (CORBA::Long, tk_long); -declare_entry (CORBA::UShort, tk_ushort); -declare_entry (CORBA::ULong, tk_ulong); - -declare_entry (CORBA::Float, tk_float); -declare_entry (CORBA::Double, tk_double); - -declare_entry (CORBA::Boolean, tk_boolean); -declare_entry (CORBA::Char, tk_char); -declare_entry (CORBA::Octet, tk_octet); -declare_entry (CORBA::Any, tk_any); - -declare_entry (CORBA::TypeCode_ptr, tk_TypeCode); -declare_entry (CORBA::Principal_ptr, tk_Principal); -declare_entry (CORBA::Object_ptr, tk_objref); - -declare_entry (CORBA::String, tk_string); -declare_entry (CORBA::OctetSeq, tk_sequence); - -declare_entry (CORBA::LongLong, tk_longlong); -declare_entry (CORBA::ULongLong, tk_ulonglong); -declare_entry (CORBA::LongDouble, tk_longdouble); -declare_entry (CORBA::WChar, tk_wchar); -declare_entry (CORBA::WString, tk_wstring); - -void -__TC_init_table (void) -{ - setup_entry (CORBA::Short, tk_short); - setup_entry (CORBA::Long, tk_long); - setup_entry (CORBA::UShort, tk_ushort); - setup_entry (CORBA::ULong, tk_ulong); - - setup_entry (CORBA::Float, tk_float); - setup_entry (CORBA::Double, tk_double); - - setup_entry (CORBA::Boolean, tk_boolean); - setup_entry (CORBA::Char, tk_char); - setup_entry (CORBA::Octet, tk_octet); - setup_entry (CORBA::Any, tk_any); - - setup_entry (CORBA::TypeCode_ptr, tk_TypeCode); - setup_entry (CORBA::Principal_ptr, tk_Principal); - setup_entry (CORBA::Object_ptr, tk_objref); - - enum generic_enum {a, b, c, d}; - - // XXX workaround for G++ 2.6.3 bug - // setup_entry (generic_enum, CORBA::tk_enum); - table [CORBA::tk_enum].size = sizeof (generic_enum); - table [CORBA::tk_enum].alignment = sizeof (generic_enum); - - setup_entry (CORBA::String, tk_string); - setup_entry (CORBA::OctetSeq, tk_sequence); - - setup_entry (CORBA::LongLong, tk_longlong); - setup_entry (CORBA::ULongLong, tk_ulonglong); - setup_entry (CORBA::LongDouble, tk_longdouble); - setup_entry (CORBA::WChar, tk_wchar); - setup_entry (CORBA::WString, tk_wstring); -} - -#undef setup - -// For a given typecode, figure out its size and alignment needs. -// This version is used mostly when traversing other typecodes, and -// follows these rules: -// -// - Some typecodes are illegal (can't be nested inside others); -// - Indirections are allowed; -// - The whole typecode (including TCKind enum) is in the stream -// -// When the routine returns, the stream has skipped this TypeCode. -// -// "size" is returned, "alignment" is an 'out' parameter. If it is -// non-null, "tc" is initialized to hold the contents of the TypeCode; -// it depends on the contents of the original stream to be valid. -// -// XXX explore splitting apart returning the size/alignment data and -// the TypeCode initialization; union traversal would benefit a bit, -// but it would need more than that to make it as speedy as struct -// traversal. - -static size_t -calc_nested_size_and_alignment (CORBA::TypeCode_ptr tc, - CDR *original_stream, - size_t &alignment, - CORBA::Environment &env) -{ - // Get the "kind" ... if this is an indirection, this is a guess - // which will soon be updated. - CORBA::ULong temp; - CORBA::TCKind kind; - - if (original_stream->get_ulong (temp) == CORBA::B_FALSE) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - env.clear (); - kind = (CORBA::TCKind) temp; - - // Check for indirection, setting up the right CDR stream to use - // when getting the rest of the parameters. (We rely on the fact - // that indirections may not point to indirections.) - CDR indirected_stream; - CDR *stream; - - if (kind == ~0) - { - CORBA::Long offset; - - // Get indirection, sanity check it, set up new stream pointing - // there. - // - // XXX access to "real" size limit for this typecode and use it - // to check for errors before indirect and to limit the new - // stream's length. ULONG_MAX is too much! - - if (!original_stream->get_long (offset) - || offset >= -8 - || ((-offset) & 0x03) != 0) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - // offset -= 4; // correct for get_long update - - indirected_stream.next = original_stream->next + (ptr_arith_t) offset; - indirected_stream.remaining = (size_t) ULONG_MAX; - stream = &indirected_stream; - - // Fetch indirected-to TCKind, deducing byte order. - - if (*indirected_stream.next == 0) // big-endian? - indirected_stream.do_byteswap = (TAO_ENCAP_BYTE_ORDER != 0); - else - indirected_stream.do_byteswap = (TAO_ENCAP_BYTE_ORDER == 0); - - if (!indirected_stream.get_ulong (temp)) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - kind = (CORBA::TCKind) temp; - - } - else - stream = original_stream; - - // Check for illegal TCKind enum values ... out of range, or which - // represent data values that can't be nested. (Some can't even - // exist freestanding!) - - if (kind >= TC_KIND_COUNT - || kind <= CORBA::tk_void - || kind == CORBA::tk_except) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Use attribute calculator routine if it exists; these are needed - // only for variable-sized data types, with encapsulated parameter - // lists that affect the size and alignment of "top level" memory - // needed to hold an instance of this type. - - if (table [kind].calc != 0) - { - assert (table [kind].size == 0); - - // Pull encapsulation length out of the stream. - if (stream->get_ulong (temp) == CORBA::B_FALSE) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Initialize the TypeCode if requested - if (tc) - { - tc->kind_ = kind; - tc->buffer_ = stream->next; - tc->length_ = temp; - } - - // Set up a separate stream for the parameters; it may easily - // have a different byte order, and this is as simple a way as - // any to ensure correctness. Then use the calculator routine - // to calculate size and alignment. - - CDR sub_encapsulation; - size_t size; - - assert (temp <= UINT_MAX); - sub_encapsulation.setup_encapsulation (stream->next, (size_t) temp); - size = table [kind].calc (&sub_encapsulation, alignment, env); - - // Check for garbage at end of parameter lists, or other cases - // where parameters and the size allocated to them don't jive. - - stream->skip_bytes ((unsigned) temp); - if (stream->next != sub_encapsulation.next) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - return size; - } - assert (table [kind].size != 0); // fixed size data type - - // Reinitialize the TypeCode if requested; this consumes any - // TypeCode parameters in the stream. They only exist for TCKind - // values that have parameters, but which represent fixed-size data - // types in the binary representation: CORBA::tk_string, CORBA::tk_wstring, - // CORBA::tk_objref, CORBA::tk_enum, and CORBA::tk_sequence. - - if (tc) - { - CORBA::ULong len; - - tc->kind_ = kind; - switch (kind) - { - default: - assert (table [kind].skipper == 0); - break; - - case CORBA::tk_string: - case CORBA::tk_wstring: - if (stream->get_ulong (len) == CORBA::B_FALSE) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - tc->length_ = len; - break; - - case CORBA::tk_enum: - case CORBA::tk_objref: - case CORBA::tk_sequence: - if (stream->get_ulong (len) == CORBA::B_FALSE) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - tc->length_ = len; - - assert (len < UINT_MAX); - tc->buffer_ = stream->next; - stream->skip_bytes ((unsigned) len); - break; - } - - // Otherwise, consume any parameters without stuffing them into - // a temporary TypeCode. - } - else if (table [kind].skipper != 0 - && table [kind].skipper (stream) == CORBA::B_FALSE) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Return statically known values. - alignment = table [kind].alignment; - return table [kind].size; -} - -// Given typecode bytes for a structure (or exception), figure out its -// alignment and size; return size, alignment is an 'out' parameter. -// Only "CORBA::tk_struct" (or "CORBA::tk_except") has been taken out of the stream -// parameter holding the bytes. -// -// We use a one-pass algorithm, calculating size and inter-element -// padding while recording the strongest alignment restriction. Then -// we correct the size to account for tail-padding. -// -// This routine recognizes that exceptions are just structs with some -// additional information. Different environments may differ in what -// that additional information is, so this routine may need to be -// taught about compiler-specific representation of that additional -// "RTTI" data. - -static size_t -calc_struct_and_except_attributes (CDR *stream, - size_t &alignment, - CORBA::Boolean is_exception, - CORBA::Environment &env) -{ - CORBA::ULong members; - size_t size; - - // Exceptions are like structs, with key additions (all of which - // might need to be be applied to structures!): vtable, typecode, - // and refcount. The size must include these "hidden" members. - // - // NOTE: in environments with "true" C++ exceptions, there may need - // to be a slot for additional "RTTI" information; maybe it is part - // of the vtable, or maybe not. Or, that information (needed to - // determine which 'catch' clauses apply) may only be provided by - // the compiler to the runtime support for the "throw" statement. - - if (is_exception) - { - size = sizeof (CORBA::Exception); - alignment = table [CORBA::tk_TypeCode].alignment; - } - else - { - alignment = 1; - size = 0; - } - - // skip rest of header (type ID and name) and collect the number of - // struct members - - if (!stream->skip_string () - || !stream->skip_string () - || !stream->get_ulong (members)) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // iterate over all the members, skipping their names and looking - // only at type data. - - for ( ; members != 0; members--) { - size_t member_size; - size_t member_alignment; - - // Skip name of the member. - if (!stream->skip_string ()) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Get size and alignment of the member, accounting for - // indirection and the various kinds of parameter encoding. - - member_size = calc_nested_size_and_alignment (0, - stream, - member_alignment, - env); - if (env.exception () != 0) - return 0; - - // Round up the struct size to handle member alignment (by adding - // internal padding), then update the current size to handle the - // member's size. - - size = (size_t) align_binary (size, member_alignment); - size += member_size; - - // Finally update the overall structure alignment requirement, if - // this element must be more strongly aligned. - - if (member_alignment > alignment) - alignment = member_alignment; - }; - - // Round up the structure size to match its overall alignment. This - // adds tail padding, if needed. - return (size_t) align_binary (size, alignment); -} - -// Calculate size and alignment for a structure. - -static size_t -calc_struct_attributes (CDR *stream, - size_t &alignment, - CORBA::Environment &env) -{ - return calc_struct_and_except_attributes (stream, - alignment, - CORBA::B_FALSE, - env); -} - -// Calculate size and alignment for an exception. - -static size_t -calc_exception_attributes (CDR *stream, - size_t &alignment, - CORBA::Environment &env) -{ - return calc_struct_and_except_attributes (stream, - alignment, - CORBA::B_TRUE, - env); -} - -// Calculate and return sizes for both parts of a union, as needed by -// other code. Return value is the overall size. The padded size of -// the discriminant is needed to traverse the two values separately. -// Unfortunately that is not quite practical to do with a single pass -// over the typecode: the inter-element padding changes depending on -// the strictest alignment required by _any_ arm of the union. - -size_t -calc_key_union_attributes (CDR *stream, - size_t &overall_alignment, - size_t &discrim_size_with_pad, - CORBA::Environment &env) -{ - CORBA::ULong members; - CORBA::ULong temp; - size_t discrim_size; - size_t value_alignment; - size_t value_size; - - overall_alignment = value_alignment = 1; - value_size = discrim_size_with_pad = 0; - - // Skip initial optional members (type ID and name). - - if (!stream->skip_string () // type ID - || !stream->skip_string ()) - { // typedef name - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Calculate discriminant size and alignment: it's the first member - // of the "struct" representing the union. We detect illegal - // discriminant kinds a bit later. - - CORBA::TypeCode discrim_tc (CORBA::tk_void); - - discrim_size = calc_nested_size_and_alignment (&discrim_tc, - stream, - overall_alignment, - env); - if (env.exception () != 0) - return 0; - - // skip "default used" indicator, and save "member count" - - if (!stream->get_ulong (temp) // default used - || !stream->get_ulong (members)) - { // member count - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // iterate over the tuples for all the members; all we care about is - // their types, which can affect either alignment or padding - // requirement for the union part of the construct. - - for ( ; members != 0; members--) { - size_t member_size, member_alignment; - - // Skip member label; its size varies with discriminant type, but - // here we don't care about its content. This is where illegal - // discriminant kinds are detected. - // - // NOTE: This modifies 94-9-32 Appendix A to stipulate that - // "long long" values are not legal as discriminants. - - switch (discrim_tc.kind_) - { - case CORBA::tk_short: - case CORBA::tk_ushort: - case CORBA::tk_wchar: - { - CORBA::Short s; - - if (!stream->get_short (s)) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - } - break; - - case CORBA::tk_long: - case CORBA::tk_ulong: - case CORBA::tk_enum: - { - CORBA::Long l; - - if (!stream->get_long (l)) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - } - break; - - case CORBA::tk_boolean: - case CORBA::tk_char: - { - char c; - - if (!stream->get_byte (c)) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - } - break; - - default: - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // We also don't care about any member name. - - if (!stream->skip_string ()) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Get the member size and alignment. - - member_size = calc_nested_size_and_alignment (0, - stream, - member_alignment, - env); - if (env.exception () != 0) - return 0; - - // Save the largest member and alignment. They don't need to be - // changed in sync -- e.g. "long double" size is larger than its - // alignment restriction on SPARC, x86, and some m68k platforms. - if (member_size > value_size) - value_size = member_size; - if (member_alignment > value_alignment) - value_alignment = member_alignment; - } - - // Round up the discriminator's size to include padding it needs in - // order to be followed by the value. - discrim_size_with_pad = (size_t) align_binary (discrim_size, - value_alignment); - - // Now calculate the overall size of the structure, which is the - // discriminator, inter-element padding, value, and tail padding. - // We know all of those except tail padding, which is a function of - // the overall alignment. (Ensures that arrays of these can be - // safely allocated and accessed!) - - if (value_alignment > overall_alignment) - overall_alignment = value_alignment; - - return (size_t) align_binary (discrim_size_with_pad + value_size, - overall_alignment); -} - -// Calculate size and alignment for a CORBA discriminated union. -// -// Note that this is really a two-element structure. The first -// element is the discriminator; the second is the value. All normal -// structure padding/alignment rules apply. In particular, all arms -// of the union have the same initial address (adequately aligned for -// any of the members). - -static size_t -calc_union_attributes (CDR *stream, - size_t &alignment, - CORBA::Environment &env) -{ - size_t scratch; - - return calc_key_union_attributes (stream, alignment, scratch, env); -} - -// Calculate size and alignment for a typedeffed type. - -static size_t -calc_alias_attributes (CDR *stream, - size_t &alignment, - CORBA::Environment &env) -{ - // Skip type ID and name in the parameter stream - - if (!stream->skip_string () // type ID - || !stream->skip_string ()) // typedef name - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // The typedef is identical to the type for which it stands. - return calc_nested_size_and_alignment (0, stream, alignment, env); -} - -// Calculate size and alignment of an array. (All such arrays are -// described as single dimensional, even though the IDL definition may -// specify a multidimensional array ... such arrays are treated as -// nested single dimensional arrays.) - -static size_t -calc_array_attributes (CDR *stream, - size_t &alignment, - CORBA::Environment &env) -{ - size_t member_size; - CORBA::ULong member_count; - - // get size and alignment of the array member - - member_size = calc_nested_size_and_alignment (0, stream, alignment, env); - if (env.exception () != 0) - return 0; - - // Get and check count of members. - - if (stream->get_ulong (member_count) == CORBA::B_FALSE - || member_count > UINT_MAX) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - - // Array size is a function only of member number and count - return member_size * (size_t) member_count; -} - -// Visit each of the elements of a structure. - -static CORBA::TypeCode::traverse_status -struct_traverse (CDR *stream, - const void *value1, - const void *value2, - CORBA::TypeCode::traverse_status (_FAR *visit) - (CORBA::TypeCode_ptr tc, - const void *value1, - const void *value2, - void *context, - CORBA::Environment &env), - void *context, - CORBA::Environment &env) -{ - // Skip over the type ID and type name in the parameters, then get - // the number of members. - CORBA::ULong members; - - if (!stream->skip_string () // type ID - || !stream->skip_string () // type name - || !stream->get_ulong (members)) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return CORBA::TypeCode::TRAVERSE_STOP; - } - - // Visit each member of the structure/exception. The initial - // pointer(s) point at the first values to visit. For structs we - // could avoid the inter-member padding ... not for the case of - // exceptions. No big deal. - // - // NOTE: For last element, could turn visit() call into something - // subject to compiler's tail call optimization and thus save a - // stack frame. - - CORBA::TypeCode::traverse_status retval; - - for (retval = CORBA::TypeCode::TRAVERSE_CONTINUE; - members != 0 && retval == CORBA::TypeCode::TRAVERSE_CONTINUE; - members--) - { - CORBA::TypeCode member_tc (CORBA::tk_null); - size_t size; - size_t alignment; - - // Skip the member's name in the parameter list. - - if (!stream->skip_string ()) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return CORBA::TypeCode::TRAVERSE_STOP; - } - - // Get the member's size, alignment, and a temporary TypeCode, - // skipping that TypeCode in the stream as we do so. - // - // This accounts for all variations: different or nonexistent - // parameter lists, errors such as out-of-range TCKind values or - // nested exceptions, and indirected typecodes. - - size = calc_nested_size_and_alignment (&member_tc, - stream, - alignment, - env); - if (env.exception () != 0) - return CORBA::TypeCode::TRAVERSE_STOP; - - // Pad the value pointers to account for the alignment - // requirements of this member, then visit. - - value1 = ptr_align_binary ((const u_char *) value1, alignment); - value2 = ptr_align_binary ((const u_char *) value2, alignment); - - retval = visit (&member_tc, value1, value2, context, env); - - // Update 'value' pointers to account for the size of the values - // just visited. - value1 = size + (char *)value1; - value2 = size + (char *)value2; - - if (env.exception () != 0) - retval = CORBA::TypeCode::TRAVERSE_STOP; - } - - return retval; -} - -// cast the discriminant values to the right type and compare them. - -static CORBA::Boolean -match_value (CORBA::TCKind kind, - CDR *tc_stream, - const void *value, - CORBA::Environment &env) -{ - CORBA::Boolean retval = CORBA::B_FALSE; - - switch (kind) - { - case CORBA::tk_short: - case CORBA::tk_ushort: - { - CORBA::UShort discrim; - - if (tc_stream->get_ushort (discrim) != CORBA::B_FALSE) - retval = (discrim == *(CORBA::UShort *)value); - else - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - break; - - case CORBA::tk_long: - case CORBA::tk_ulong: - { - CORBA::ULong discrim; - - if (tc_stream->get_ulong (discrim) != CORBA::B_FALSE) - retval = (discrim == *(CORBA::ULong *)value); - else - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - break; - - case CORBA::tk_enum: - { - CORBA::ULong discrim; - - if (tc_stream->get_ulong (discrim) != CORBA::B_FALSE) - retval = (discrim == *(unsigned *)value); - else - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - break; - - case CORBA::tk_boolean: - { - CORBA::Boolean discrim; - - if (tc_stream->get_boolean (discrim) != CORBA::B_FALSE) - retval = (discrim == *(CORBA::Boolean *)value); - else - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - break; - - case CORBA::tk_char: - { - CORBA::Char discrim; - - if (tc_stream->get_char (discrim) != CORBA::B_FALSE) - retval = (discrim == *(CORBA::Char *)value); - else - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - break; - - case CORBA::tk_wchar: - { - CORBA::WChar discrim; - - if (tc_stream->get_wchar (discrim) != CORBA::B_FALSE) - retval = (discrim == *(CORBA::WChar *)value); - else - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - break; - - default: - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - } - - return retval; -} - -// Visit the two elements of the union: the discrminant, and then any -// specific value as indicated by the discriminant of value1. - -static CORBA::TypeCode::traverse_status -union_traverse (CDR *stream, - const void *value1, - const void *value2, - CORBA::TypeCode::traverse_status (_FAR *visit) - (CORBA::TypeCode_ptr tc, - const void *value1, - const void *value2, - void *context, - CORBA::Environment &env), - void *context, - CORBA::Environment &env) -{ - size_t discrim_size_with_pad; - - // Figure out size of discriminant plus padding, used to adjust - // value pointers later. This can't be calculated without looking - // at all branches of the union ... forcing union traversal to be a - // two-pass algorithm, unless/until some data gets squirreled away. - { - CDR temp_cdr; - size_t scratch; - - temp_cdr.next = stream->next; - temp_cdr.remaining = stream->remaining; - temp_cdr.do_byteswap = stream->do_byteswap; - temp_cdr.do_free = 0; - - (void) calc_key_union_attributes (&temp_cdr, - scratch, - discrim_size_with_pad, - env); - } - if (env.exception() != 0) - return CORBA::TypeCode::TRAVERSE_STOP; - - // Skip the optional type ID and type name. - if (!stream->skip_string () // type ID, hidden - || !stream->skip_string ()) - { // typedef name - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return CORBA::TypeCode::TRAVERSE_STOP; - } - - // Get and skip the discriminant's TypeCode. This allow for - // indirection (e.g. a complex enum discriminant). We use that - // TypeCode to visit the discriminant. - // - // We know the kind is legal and the TypeCode is valid because this - // repeats work we did earlier -- so checks are omitted. - - CORBA::TypeCode discrim_tc (CORBA::tk_null); - - { - size_t scratch; - - (void) calc_nested_size_and_alignment (&discrim_tc, - stream, - scratch, - env); - } - - if (visit (&discrim_tc, - value1, - value2, - context, - env) == CORBA::TypeCode::TRAVERSE_STOP) - return CORBA::TypeCode::TRAVERSE_STOP; - - // Adjust the pointers to point to the other member of the union; - // this ensures alignment for any of the values. Save the pointer - // to the discriminant though; we need it to find out which member - // to visit! - - const void *discrim_ptr = value1; - - value1 = discrim_size_with_pad + (char *) value1; - value2 = discrim_size_with_pad + (char *) value2; - - // Get the flag that tells if there's a "default" arm in this union, - // then the number of members in the union. - - CORBA::Long default_used = 0; - CORBA::ULong member_count; - - if (!stream->get_long (default_used)) - { - // default used - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return CORBA::TypeCode::TRAVERSE_STOP; - } - - if (!stream->get_ulong (member_count)) - { // member count - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return CORBA::TypeCode::TRAVERSE_STOP; - } - - // Scan to find the tuple whose value matches the discriminator. - // - // While we're scanning, record any default arm's information. If - // we can't find a match for the discriminant value, that arm will - // be used later. - - u_char *default_tc_ptr = 0; - size_t default_tc_len = 0; - - while (member_count-- != 0) - { - // Test to see if the discriminant value matches the one in the - // TypeCode; this skips the the discriminant value in this CDR - // stream. - - CORBA::Boolean discrim_matched; - - discrim_matched = match_value (discrim_tc.kind_, - stream, - discrim_ptr, - env); - if (env.exception () != 0) - return CORBA::TypeCode::TRAVERSE_STOP; - - // Skip the name of the member; we never care about it. - - if (!stream->skip_string ()) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return CORBA::TypeCode::TRAVERSE_STOP; - } - - // If this is the default member, remember where its typecode - // data is stored; we'll use it later. - - if (default_used >= 0 && default_used-- == 0) - { - default_tc_ptr = stream->next; - default_tc_len = stream->remaining; - } - - // Get the TypeCode for this member. - // - // XXX we really don't care about size and alignment this time, - // only that we initialize the TypeCode. - - CORBA::TypeCode tc (CORBA::tk_null); - size_t scratch; - - (void) calc_nested_size_and_alignment (&tc, stream, scratch, env); - if (env.exception () != 0) - return CORBA::TypeCode::TRAVERSE_STOP; - - // If we matched, visit the member and return. - if (discrim_matched) - return visit (&tc, value1, value2, context, env); - } - - // If we get here, it means any default arm should be used. We know - // at least the basic sanity checks passed; we don't repeat. - - if (default_tc_ptr) - { - CDR temp_str; - size_t scratch; - CORBA::TypeCode tc (CORBA::tk_null); - - temp_str.next = default_tc_ptr; - temp_str.remaining = default_tc_len; - temp_str.do_byteswap = stream->do_byteswap; - - // Get and use the TypeCode. - // - // XXX we really don't care about size and alignment this time, - // only that we initialize the TypeCode. - - (void) calc_nested_size_and_alignment (&tc, &temp_str, scratch, env); - return visit (&tc, value1, value2, context, env); - } - return CORBA::TypeCode::TRAVERSE_CONTINUE; -} - -// For each node in "data", visit it. For singleton nodes that's all -// but a NOP; for structs, unions, etc it's more interesting. The -// visit routine can descend, if it chooses. -// -// NOTE: this does no memory allocation or deallocation except through -// use of the stack. Or at least, it should do none -- if you find -// that just traversing a data value allocates any memory, that's a -// bug to fix! - -CORBA::TypeCode::traverse_status -CORBA::TypeCode::traverse (const void *value1, - const void *value2, - CORBA::TypeCode::traverse_status (_FAR *visit) - (CORBA::TypeCode_ptr tc, - const void *value1, - const void *value2, - void *context, - CORBA::Environment &env), - void *context, - CORBA::Environment &env) -{ - env.clear (); - - // Quickly accomodate the bulk of cases, which are just (tail) calls - // to the visit() routine. We take advantage of the fact that these - // are largely in a convenient numeric range to work around poor - // optimization of "switch" code in some compilers. This - // improvement has in some cases been more than 5% faster - // (significant). - // - // NOTE: if for some reason the constants in the protocol spec - // (including Appendix A) change, this logic may need to be verified - // again. Luckily, changing protocol constants is quite rare; they - // normally just get added to (at the end). - // - if (kind_ <= CORBA::tk_objref - || (CORBA::tk_longlong <= kind_ && kind_ <= CORBA::tk_wstring)) - return visit (this, value1, value2, context, env); - - // Handle the cases that aren't in convenient numeric ranges. - - traverse_status retval; - - switch (kind_) - { - case CORBA::tk_string: - case CORBA::tk_enum: - return visit (this, value1, value2, context, env); - - // Typedefs just add a delay, while we skip the typedef ID - // and name ... - - case CORBA::tk_alias: - { - CORBA::TypeCode_ptr tcp; - CORBA::Environment env2; - - // XXX rework for efficiency, this doesn't need to allocate - // memory during the traversal! - - tcp = typecode_param (2, env); - if (env.exception () != 0) - return TRAVERSE_STOP; - - retval = tcp->traverse (value1, value2, visit, context, env); - - tcp->Release (); - } - return retval; - - // Exceptions in-memory are structures, except that there are data - // members "hidden" in front: vtable, typecode, refcount. We skip - // them, and allow the traversal code to account for the internal - // padding before the other elements of the exception. - // - // NOTE: see header comment re treatment of these values as "real" - // C++ exceptions. C++ RTTI data might need to be skipped. Also, - // see the comments in unmarshaling code: hard to throw these - // values. - // - // Not enough of the exception runtime is public for binary - // standards to exist for C++ exceptions yet. Compiler-specific - // code will need to handle examining, unmarshaling, and throwing - // of CORBA exceptions (in C++ environments) for some time. - case CORBA::tk_except: - value1 = sizeof (CORBA::Exception) + (char *) value1; - value2 = sizeof (CORBA::Exception) + (char *) value2; - // FALLTHROUGH - - case CORBA::tk_struct: - // XXX for OLE Automation, we'll probably need BOTH exceptions - // and structs to inherit IUnknown, hence we'll need to be - // skipping the vtable pointer ... - { - // Create the sub-encapsulation stream that holds the - // parameters for the typecode. - - CDR stream; - - stream.setup_encapsulation (buffer_, (size_t) length_); - - return struct_traverse (&stream, value1, value2, - visit, context, env); - } - - case CORBA::tk_union: - { - // visit the discriminant, then search the typecode for the - // relevant union member and then visit that member. - CDR stream; - - stream.setup_encapsulation (buffer_, (size_t) length_); - - return union_traverse (&stream, value1, value2, - visit, context, env); - } - - // Sequences are just arrays with bound determined at runtime, - // rather than compile time. Multidimensional arrays are nested - // C-style: the leftmost dimension in the IDL definition is - // "outermost", etc. - { - CORBA::TypeCode_ptr tc2; - size_t size; - CORBA::ULong bounds; - CORBA::OctetSeq *seq; - - case CORBA::tk_sequence: - // Find out how many elements there are, and adjust the data - // pointers to point to those elements rather than to the - // sequence itself. - seq = (CORBA::OctetSeq *)value1; - - bounds = seq->length; - value1 = seq->buffer; - - if (value2) - { - seq = (CORBA::OctetSeq *)value2; - value2 = seq->buffer; - } - goto shared_seq_array_code; - - case CORBA::tk_array: - // Array bounds are in the typecode itself. - bounds = ulong_param (1, env); - if (env.exception () != 0) - return TRAVERSE_STOP; - - shared_seq_array_code: - // Find element's type, and size ... - tc2 = typecode_param (0, env); - if (env.exception () != 0) - return TRAVERSE_STOP; - - size = tc2->size (env); - if (env.exception () != 0) - return TRAVERSE_STOP; - - // ... then visit the elements in order. - // - // NOTE: for last element, could turn visit() call into - // something subject to compiler's tail call optimization and - // thus save a stack frame - while (bounds--) - { - if (visit (tc2, value1, value2, context, env) == TRAVERSE_STOP) - return TRAVERSE_STOP; - - value1 = size + (char *) value1; - value2 = size + (char *) value2; - } - CORBA::release (tc2); - env.clear (); - } - return TRAVERSE_CONTINUE; - - // case ~0: // indirection, illegal at top level - default: // invalid/illegal - break; - } // end switch on typecode "kind" - - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return TRAVERSE_STOP; -} - -// Tell user the size of an instance of the data type described by -// this typecode ... typically used to allocate memory. - -size_t -CORBA::TypeCode::private_size (CORBA::Environment &env) -{ - if (kind_ >= TC_KIND_COUNT) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - env.clear (); - - if (table [kind_].calc == 0) - { - private_state_->tc_size_known_ = CORBA::B_TRUE; - private_state_->tc_size_ = table [kind_].size; - return private_state_->tc_size_; - } - - size_t alignment; - CDR stream; - - stream.setup_encapsulation (buffer_, (size_t) length_); - - private_state_->tc_size_known_ = CORBA::B_TRUE; - private_state_->tc_size_ = table [kind_].calc (&stream, alignment, env); - return private_state_->tc_size_; -} - -// Tell user the alignment restriction for the data type described by -// an instance of this data type. Rarely used; provided for -// completeness. - -size_t -CORBA::TypeCode::private_alignment (CORBA::Environment &env) -{ - if (kind_ >= TC_KIND_COUNT) - { - env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); - return 0; - } - env.clear (); - - if (table [kind_].calc == 0) - { - private_state_->tc_alignment_known_ = CORBA::B_TRUE; - private_state_->tc_alignment_ = table [kind_].alignment; - return private_state_->tc_alignment_; - } - - size_t alignment; - CDR stream; - - stream.setup_encapsulation (buffer_, (size_t) length_); - - (void) table [kind_].calc (&stream, alignment, env); - private_state_->tc_alignment_known_ = CORBA::B_TRUE; - private_state_->tc_alignment_ = alignment; - return alignment; -} |