Skip to content

[BZ-1637] TypeCode redesign #1637

@jwillemsen

Description

@jwillemsen
Field Value
Bugzilla ID 1637
Reporter Nanbor Wang
Assigned to Ossama Othman
Product TAO
Component ORB
Version 1.4
Platform / OS All / All
Priority P2
Severity enhancement
Status RESOLVED
Resolution FIXED
Created 2003-11-05 10:39:43 -0600
Depends on #1369
Blocks #550, #1803

Originally posted by Nanbor Wang on 2003-11-05 10:39:43 -0600


More suggestions from Carlos


char * Test::Hello::get_string (
ACE_ENV_SINGLE_ARG_DECL
)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
if (!this->is_evaluated ())
{
ACE_NESTED_CLASS (CORBA, Object)::tao_object_initialize (this);
}

if (this->the_TAO_Hello_Proxy_Broker_ == 0)
Test_Hello_setup_collocation (
this->ACE_NESTED_CLASS (CORBA, Object)::_is_collocated ()
);
}
....
...
..
.

    you may want to change that for a single call, like:

/* private / / inline ?? */ void Test::Hello::__tao_initialize()
{
if (!this->is_evaluated ())
{
ACE_NESTED_CLASS (CORBA, Object)::tao_object_initialize (this);
}

if (this->the_TAO_Hello_Proxy_Broker_ == 0)
{
Test_Hello_setup_collocation (
this->ACE_NESTED_CLASS (CORBA, Object)::_is_collocated ()
);
}
}

char * Test::Hello::get_string (
ACE_ENV_SINGLE_ARG_DECL
)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
__tao_initialize();
....
...
..
.

    Not much difference if you only have one operation, but much

better if you have a lot.

The next change is more interesting. What can we do to reduce
the cost of the Typecodes and the Anys? First notice the following
line counts (in TAO/tests/Hello):

$ /home/coryan/UCI/ACE_wrappers/build/Linux/TAO/TAO_IDL/tao_idl -Ge 1 -
DBORG_EVENT_HEADER -St Test.idl
$ wc -l TestC.cpp
303 TestC.cpp

$ /home/coryan/UCI/ACE_wrappers/build/Linux/TAO/TAO_IDL/tao_idl -Ge 1 -
DBORG_EVENT_HEADER Test.idl
$ wc -l TestC.cpp
399 TestC.cpp

    Nearly 25% of the code in the C.cpp file is just Typecode

madness. In terms of build time this is even more interesting:

-- Without -St --
$ time g++ -Wwrite-strings -W -Wall -Wpointer-arith -pipe -O3 -g -D_LARGEFILE64_SOURCE -
D_REENTRANT -DACE_HA
S_AIO_CALLS -D_GNU_SOURCE -DBORG_EVENT_HEADER -I/home/coryan/UCI/ACE_wrappers/
build/Linux -I/home/coryan/UCI/A
CE_wrappers/build/Linux/TAO -DACE_HAS_EXCEPTIONS -DACE_NO_INLINE -DTAO_BUILD_DLL -
c -o foo.o TestC.cpp

real 0m2.730s
user 0m2.550s
sys 0m0.210s

-- With -St --
$ /home/coryan/UCI/ACE_wrappers/build/Linux/TAO/TAO_IDL/tao_idl -Ge 1 -
DBORG_EVENT_HEADER -St Test.idl
[coryan@glamdring Hello]$ time g++ -Wwrite-strings -W -Wall -Wpointer-arith -pipe -O3 -g -
D_LARGEFILE64_SOUR
CE -D_REENTRANT -DACE_HAS_AIO_CALLS -D_GNU_SOURCE -DBORG_EVENT_HEADER -I/home/
coryan/UCI/ACE_wrappers/build/Li
nux -I/home/coryan/UCI/ACE_wrappers/build/Linux/TAO -DACE_HAS_EXCEPTIONS -
DACE_NO_INLINE -DTAO_BUILD_DLL -cCE -D_REENTRANT -DACE_HAS_AIO_CALLS -
D_GNU_SOURCE -DBORG_EVENT_HEADER -I/home/coryan/UCI/ACE_wrappers/build/Li
nux -I/home/coryan/UCI/ACE_wrappers/build/Linux/TAO -DACE_HAS_EXCEPTIONS -
DACE_NO_INLINE -DTAO_BUILD_DLL -c
-o foo.o TestC.cpp

real 0m1.924s
user 0m1.810s
sys 0m0.150s

    That's nearly a 40% improvement!  I'll admit this is a small

file, anything with lots of operations and no types will not look this
good, but something with lots of types and no operations will look
much better :-)

    Furthermore, the Typecode.h files in the ORB are bloated and

slow to compile.

    What I will propose is that we completely change the way we

generate Typecode information. First we need to remember that a
Typecode, after it is completely extracted, is simply a hierarchal
data structure that represents the elements in an IDL construct. What
we could do is create this hierarchy directly, skipping the
intermediate binary representation.

    The solution below should work, I can only find one problem

with it: it does not work if B.idl includes (and uses types from)
A.idl but A.idl was compiled without -St.... Frankly, this
ill-defined at best. I have some solutions to offer there (read [*])

    Before we go into abstractions, let me give you an example,

suppose we have IDL like this:

typedef long Token;

struct Quz {
Token first_token;
Token second_token;
string the_string;
};

union Foo switch(short) {
case 0:
case 1: short bar;
case 2: Quz the_quz;
default: Token baz;
};

    I think if we generate code like this:

// C++ (*C.cpp file)
TAO::Alias_TypeCode _tao_tc_Token("IDL:Token/1.0", "Token", &CORBA::_tc_long);
CORBA::TypeCode_ptr _tc_Token = &_tao_tc_Token;

   first notice that the *value* of CORBA::_tc_long is not know

at compile time, but its address is known (or at least well-defined)
at compile time. Naturally the TAO::Alias_TypeCode class will have to
derive from CORBA::TypeCode, and it will need to know how to use the
parameters effectively. I'll show how to implement such classes in a
second.

    Structures are easy:

// C++ (*C.cpp file)
TAO::TypeCode_Field _tao_fields_tc_Quz[] = {
{ "first_token", &_tc_Token },
{ "second_token", &_tc_Token },
{ "the_string", &CORBA::_tc_string },
};
TAO::Struct_TypeCode _tao_tc_Quz(
"IDL:Quz/1.0", "Quz",
_tao_fields_tc_Quz, sizeof(_tao_fields_tc_Quz));

    here I can show some of the implementation:

namespace TAO {
class Struct_TypeCode
: public CORBA::TypeCode // This should be abstract
{
public:
Struct_TypeCode(
char const * id,
char const * name,
TAO::TypeCode_Field * fields,
size_t nfields)
: id_(id)
, name_(name)
, fields_(fields)
, nfields_(nfields)
{ }

virtual CORBA::TCKind() const { return tk_struct; }
char const * id() const { return id
; }
char const * name() const { return name_; }
CORBA::ULong member_count() const { return nfields_; }
char const * member_name(CORBA::ULong i) const
{
if(i >= nfields_) {
throw ....;

return fields_[i].name_;

}
CORBA::TypeCode_ptr member_type(CORBA::ULong i) const
{
if(i >= nfields_) {
throw ....;

return *(fields_[i].type_); // notice the indirection

}

// operations that do not make sense are supposed to throw...
CORBA::TypeCode_ptr discriminator_type() const {
throw BadKind();
}
};

    as you can see very is straightforward.  I think

arrays, sequences, interfaces and stuff like that are simple too.
Unions are a little more tricky:

// C++ (*C.cpp file)
TAO::TypeCode_Branch _tao_branches_tc_Foo[] = {
{ 0, "bar", &CORBA::_tc_short },
{ 1, "bar", &CORBA::_tc_short },
{ 2, "the_quz", &_tc_Quz },
};
TAO::Struct_TypeCode _tao_tc_Foo(
"IDL:Foo/1.0", "Foo",
&CORBA::_tc_short, // discriminator
_tao_branches_tc_Foo, sizeof(_tao_branches_tc_Foo),
"baz", &_tc_Token // default (could be NULL if there is none)
);

    I think recursive types simply work too, as in:

// IDL
struct Recursive;
typedef sequence Recursion;
struct Recursive {
long x;
Recursion y;
};

// C++ (Header)
CORBA::TypeCode_ptr _tc_Recursive;
CORBA::TypeCode_ptr _tc_Recursion;

// C++ (CPP)
TAO::Alias_TypeCode _tao_tc_Recursion(.. &_tc_Recursive ...); // legal!
CORBA::TypeCode_ptr _tc_Recursion = &_tao_tc_Recursion;

TAO::Struct_TypeCode _tao_tc_Recursive(.. &_tc_Recursion ...); // OK!
CORBA::TypeCode_ptr _tc_Recursive = &_tao_tc_Recursive;

_tao_branches_tc_Foo, sizeof(_tao_branches_tc_Foo),
"baz", &_tc_Token // default (could be NULL if there is none)
);

    I think recursive types simply work too, as in:

// IDL
struct Recursive;
typedef sequence Recursion;
struct Recursive {
long x;
Recursion y;
};

// C++ (Header)
CORBA::TypeCode_ptr _tc_Recursive;
CORBA::TypeCode_ptr _tc_Recursion;

// C++ (CPP)
TAO::Alias_TypeCode _tao_tc_Recursion(.. &_tc_Recursive ...); // legal!
CORBA::TypeCode_ptr _tc_Recursion = &_tao_tc_Recursion;

TAO::Struct_TypeCode _tao_tc_Recursive(.. &_tc_Recursion ...); // OK!
CORBA::TypeCode_ptr _tc_Recursive = &_tao_tc_Recursive;

 The demarshaling code to receive typecodes from the wire will

have to get smarter, but that's hidden in the library.

                            Let me know what you think.

[*] So what if B.idl did not define _tc_Foo but A.idl needs it?
Several solutions:

  • If we successfully eliminate the motivation for the -St option,
    then we can remove the option and avoid the problem completely!

  • The application is invoking undefined behavior, i.e. as soon as the
    use -St they are outside the CORBA spec and we can tell them what
    the rules are. In this case "-St everywhere or nowhere."

  • Use macros to detect (at build time) if A.idl was compiled without
    -St. In that case fallback on some other mechanism, like the old
    arrays. For example, the generated code could include some macros
    like:

// AC.h
#define _tao_compile_trait__A_IDL__with_St

    which are used like this:

// BC.cpp

#if defined(_tao_compile_trait__A_IDL__with_St)
// Generate _tc_Foo here
namespace {
CORBA::TypeCode _tc_Foo = ....;
}
#endif

    Using macros will probably fail when the filenames or the

type names are ambiguous. One could dream of template
meta-programming techniques to work around that, but it is overkill.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions