summaryrefslogtreecommitdiff
path: root/TAO/tao/interp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/tao/interp.cpp')
-rw-r--r--TAO/tao/interp.cpp1504
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;
-}