1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
|
%% -*- mode: LaTeX -*-
%%
%% Copyright (c) 1995, 1996, 1999 The University of Utah and the Computer
%% Systems Laboratory at the University of Utah (CSL).
%%
%% This file is part of Flick, the Flexible IDL Compiler Kit.
%%
%% Flick is free software; you can redistribute it and/or modify it under the
%% terms of the GNU General Public License as published by the Free Software
%% Foundation; either version 2 of the License, or (at your option) any later
%% version.
%%
%% Flick is distributed in the hope that it will be useful, but WITHOUT ANY
%% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
%% FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
%% details.
%%
%% You should have received a copy of the GNU General Public License along with
%% Flick; see the file COPYING. If not, write to the Free Software Foundation,
%% 59 Temple Place #330, Boston, MA 02111, USA.
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Back Ends}
\label{cha:BE}
The presentation created by the presentation generators contains only the
outside view, the language presentation and behavior, of a series of functions.
To create the actual implementations of these presentations they need to be fed
into a back end code generator. There are several distinct back ends which are
based on a common library that does most of the work. The library and specific
back ends are located under the \filename{c/pbe} directory.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{The Back End Library}
\label{sec:BE:The Back End Library}
The back end library is the base implementation for code generation which is
then specialized to an encoding scheme and runtime. The library provides a
great deal of infrastructure for dealing with various things, like command line
arguments, and loading the \PRESC{} input file. However, the primary job of
the library is to handle the translation and optimization of the input \PRESC{}
descriptions into C or C++ code. The process of interpreting the \PRESC{} tree
falls to the \ctype{mu_state} family of classes which provide a number of
functions for walking the tree and interpreting its nodes. The
\ctype{mu_state} can then be overridden by specific back ends to implement
their own functionality. In addition to generating code from the \PRESC{}
description of stubs, the back end can also employ \SCML{} code to generate
formatted C and C++ source code. This \SCML{} code is usually defined
externally and then called explicitly by the back end. The process of calling
\SCML{} macros can be done manually as it is for creating the header and footer
for output files, or through the presentation implementation and collection
classes described later.
The declarations for the library classes and functions can be found in the
\filename{mom/c/be} directory and the source in \filename{c/pbe/lib}.
\subsection{Back End State}
\label{subsec:BE:Back End State}
The first set of classes we'll look at are used for maintaining state in the
back end and managing the top level flow of control. The classes and functions
work together based on a simple event based methodology to allow for easy
expansion. The core of this model is a handler object which can process an
event, it does not necessarily have to process every event, just the ones it is
interested in. These handlers are then prioritized and collected into an
object which is able to distribute a single event amongst its set of handlers.
The resulting system allows for easy addition of code into the root control
path without having to tamper directly with the library.
Types:
\begin{ctypelist}
\item[be_event] A simple structure which has an event identifier and
can be subclassed to contain extra information about an event.
\item[be_handler] Contains a function pointer which is expected to
handle any \ctype{be_event}s passed to it.
\item[be_looper] A subclass of \ctype{be_handler} that maintains a
list of target \ctype{be_handler}s. Whenever an event is given to the looper
it will distribute it to the target handlers.
\item[be_file] A subclass of \ctype{be_looper} that is used to track
any files in the back end as well as generate their output. The handlers
that are added to the \ctype{be_file} object are expected to generate the
output for that file.
\item[be_state] A subclass of \ctype{be_looper} that acts as the
primary event handler and dumping ground for anything a back end might be
interested in. Handlers added to a \ctype{be_state} object are used for
initializing variables, reacting to command line arguments and directing
the \ctype{be_files} to generate themselves.
\end{ctypelist}
Functions:
\begin{cprototypelist}
\item[be_state *get_be_state()] Retrieve the \ctype{be_state}
object for a specific back end
\item[int main(int argc, char **argv)] The library provided
\cfunction{main} simply gets a \ctype{be_state} from
\cfunction{get_be_state()} and then installs any handlers. Next, the command
line arguments are passed to the \ctype{be_state} for processing and finally
it is all set in motion by sending the initialize, command line args, and
shutdown events to the \ctype{be_state}.
\end{cprototypelist}
The current set of handler functions can be found in
\filename{c/pbe/lib/arg_handlers.cc}, \filename{c/pbe/lib/state_handlers.cc},
and \filename{c/pbe/lib/file_handlers.cc}. The handlers are all relatively
simple, they just react to whatever events they are interested in and can then
choose what to do from there. Currently, only the IIOPXX back end installs its
own handler: it squelches the output of any definitions from the
\filename{orb.idl} file after the \PRES{} has been read in by the earlier
handlers.
\subsection{Stub Generators}
\label{subsec:BE:Stub Generators}
Once the flow of control comes down from the high level handler functions, we
finally get to generate the contents of a file. The handlers in
\filename{file_handlers.cc} take care of this by calling stub generation
functions for each stub described in the \PRESC{}. The functions provided by
the back end library are empty for the most part since they are expected to be
implemented by the specific back end: information is required about the runtime
in order to generate correct code.
Type marshaling and unmarshaling stubs are generated a bit different from
regular client and server stubs. Since they are rarely used, we generate them
on demand to prevent excessive output. Whenever one of these stubs is needed
(a call to the stub is generated in the code), we create an
\ctype{mu_stub_info_node} and store a reference to the stub and how it is
going to be used (parameter direction and byteswap flag). This node is then
put into a list kept by the \ctype{be_state}. After all other stubs have been
generated, the set of required marshal/unmarshal stubs are generated by
traversing the list.
\begin{cprototypelist}
\item[void w_stub(pres_c_1 *pres, int idx)] This will dispatch
to one of the functions below depending on the type of stub. The stubs below
are meant to be overridden by the back end since they tend to be specific to
the runtime.
\item[void w_marshal_stub(pres_c_1 *pres, int idx)] Writes out a marshaling
stub for a specific data type. The base library defines this to do nothing.
\item[void w_unmarshal_stub(pres_c_1 *pres, int idx)] Writes out an
unmarshaling stub for a specific data type. The base library defines this to
do nothing.
\item[void w_client_stub(pres_c_1 *pres, int stub_idx)] Writes out a client
\RPC{} stub. This is left undefined in the base library; the responsibility
belongs entirely to the specific back end how a client stub is generated.
\item[void w_skel(pres_c_1 *pres, int stub_idx)] Writes out a server or
client skeleton (dispatch function). This is left undefined in the base
library; the responsibility belongs entirely to the specific back end how a
skeleton is generated.
\item[void w_send_stub(pres_c_1 *pres, int stub_idx)] Writes out a stub meant
only for sending a specific message type (part of the decomposed stub model).
The base library version causes a warning to be emitted, and no code is
generated.
\item[void w_recv_stub(pres_c_1 *pres, int stub_idx)] Writes out a stub meant
only for receiving a specific message type (part of the decomposed stub
model). The base library version causes a warning to be emitted, and no code
is generated.
\item[void w_msg_marshal_stub(pres_c_1 *pres, int idx)] Writes out a stub
meant for marshaling a complete, specific message type (part of the
decomposed stub model). The base library version causes a warning to be
emitted, and no code is generated.
\item[void w_msg_unmarshal_stub(pres_c_1 *pres, int idx)] Writes out a stub
meant for unmarshaling a complete, specific message type (part of the
decomposed stub model). The base library version causes a warning to be
emitted, and no code is generated.
\item[void w_continue_stub(pres_c_1 *pres, int idx)] Writes out a stub meant
for continuing a delayed message (part of the decomposed stub model). The
base library version causes a warning to be emitted, and no code is
generated.
\item[void do_main_output(pres_c_1 *pres)] This can be used to write out a
main function for a server. By default, nothing is generated.
\item[void make_interface_graph(pres_c_1 *pres)] This is a bit
of a hack used to get information about runtime type information into source
code. This is only really used to help implement \CORBA{}'s \idl{is_a}
operation. The function will write out a data structure containing
information about interface inheritance which is then used by the runtime
\idl{is_a} function.
\end{cprototypelist}
\subsection{mu\_state}
\label{subsec:BE:mustate}
The \ctype{mu_state} C++ class is the primary mechanism for creating marshaling
and unmarshaling code. An object of this class is created and initialized with
the necessary data structures from the \PRESC{} and then set in motion to
create the code. Basically, this code creation is done by interpreting the
intentions of the \PRESC{} nodes in the presence of specific state options, set
at initialization or by context, to produce the actual code. The class itself
is simply made up of a set of functions, each handling a single \PRESC{} node.
Each function does some processing on the node, which may include using the
\ctype{mu_state} to process any child nodes. Thus, flexibility comes from
overriding these functions to specialize them to the needs of a back end. Any
code produced is stored in \CAST{} blocks rather than directly writing to the
file, since we we may want to perform some post-processing on the generated
code. Finally, the user of the \ctype{mu_state} takes whatever \CAST{} is left
after processing and wraps it with whatever boilerplate code is necessary for a
complete construct.
\subsubsection{Walking the PRES_C tree}
\label{subsubsec:BE:Walking the PRESC tree}
Processing a \PRESC{} node usually requires more information than is contained
in the node itself. This is due to the structure of the \PRESC{} tree; since
it does not always encode references to \CAST{} and \MINT{} structures, these
need to be walked in parallel. This is why some functions require arguments
for \CAST{} and \MINT{} structures, however, a \PRESC{} node does not
necessarily have to traverse the structures. For example, a
\cidentifier{PRES_C_MAPPING_POINTER} will pass down the C type that the pointer
is referring to, but the \MINT{} structure is not descended since it has no
representation of pointers. The functions that do not require a \CAST{} object
instead work off of a collection of \CAST{} objects accessed through an
\ctype{inline_state}. The \ctype{inline_state} is used to map indices from a
\cidentifier{PRES_C_INLINE_ATOM} to a C structure, union, or function encoded
in \CAST{}. Once, the \cidentifier{PRES_C_INLINE_ATOM} is executed the
\ctype{mu_state} goes into ``mapping'' mode and the selected \CAST{} object is
passed down to the mapping nodes. Once we've figured out what objects we're
trying to process we need to know what we're supposed to do with them. The
\cidentifier{op} slot in the \ctype{mu_state} is used for this; it can be set
with several flags that will influence the code to do what is needed by the
user. The current set of flags is:
\begin{cidentifierlist}
\item[MUST_ALLOCATE]
%
Memory should be allocated whenever it is needed. For a server stub, the
space for the unmarshaled `in' parameters and ``root'' space for the `out'
parameters that will be filled in by the work function should be allocated at
this point. For a client stub, the results contained in the reply message
may need to have space allocated so they can be returned to the client
program. In addition, this iterator should deal with any setup necessary to
begin an \RPC{}.
\item[MUST_ENCODE]
%
Appropriate values should be marshaled into the message stream. Given the
data values as parameters to the client stub or as return parameters from the
work function, they are serialized into a data stream according to the
requirements of the message format and data encoding scheme in use.
\item[MUST_DECODE]
%
Appropriate values should be unmarshaled from the message stream. The
serialized data stream is converted into the data values that can be returned
by the client stub or handed to the work function, according to the message
format and data encoding scheme in use.
\item[MUST_DEALLOCATE]
%
Memory should be deallocated when it is no longer needed (where appropriate).
More generally, this is for any type of cleanup necessary to complete an
\RPC{}.
\item[MUST_REQUEST, MUST_REPLY]
%
These indicate that the current state is handling a request or reply message,
respectively. This knowledge is implicitly held by the other flags and
whether client or server code is being generated; however, it is more
convenient to have an explicit flag to represent this. Naturally, these
flags are mutually exclusive.
\end{cidentifierlist}
\subsubsection{Marshaling Buffer Management}
\label{subsubsec:BE:Marshaling Buffer Management}
Stubs generated for non-trivial \RPC{}s generally need some kind of
\emph{marshaling buffer} or \emph{stream}, into which messages are marshaled or
from which messages are unmarshaled. Sometimes a message can use multiple
marshaling buffers. The format of the marshaled data in the buffer(s) depends
on the encoding scheme being used by the back end (e.g., \XDR{} is an encoding
scheme), and by the \MINT{} interface definition for the \RPC{} in question.
The format of the marshaled data does \emph{not} usually depend on any aspects
of presentation.
Some transport mechanisms can transfer an ``unlimited'' amount of data in one
message (e.g., Mach~3); others impose some arbitrary limit (e.g., Mach~4).
Flick stubs are generally expected to be able to handle an unlimited amount of
data, regardless of any limitations of the transport mechanism. Fixed-length
arrays are generally handled as merely a degenerate case of variable-length
arrays: the two types of arrays are identical except that fixed-length arrays
use a ``degenerate integer'' data type with only one possible value as their
length data type. Thus, fixed and variable-length arrays can usually be
marshaled in exactly the same way; the simple-integer-marshaling code will
automatically handle the degenerate length ``variable'' in fixed-length arrays
(see \filename{mu_mapping_direct.cc}).
The back end support library assumes that code generation can be done by
traversing the type trees in a certain ``natural order'':
\begin{cidentifierlist}
\item[MINT_STRUCT] Marshal each element of the struct in the same order in
which the elements appear in the presented structure. Note that the element
ordering in the \cidentifier{MINT_STRUCT} may be different from that in the
presented structure, which may in turn be different from that which is
encoded on the wire.
\item[MINT_UNION] Marshal the union discriminator first, then marshal the
selected union case.
\item[MINT_ARRAY] First marshal the array's length (if non-constant), then
marshal each element in order, lowest-indexed element first.
\end{cidentifierlist}
This ordering is not mandated; it is the responsibility of the back end to
choose an appropriate on-the-wire layout for the data, as the needs of a
particular transport mechanism dictate. For example, just because the type
graphs are traversed in the order specified above does not mean the data must
always appear in memory or on the wire in exactly this order; however, it is
generally easier to write the back end if the layouts match.
\subsubsection{Generated Code}
\label{subsubsec:BE:Generated Code}
The actual stub code that gets generated is made up of a number of macro calls
and some control flow code. The macros are all defined in the runtime header
files and follow similar naming and calling conventions across implementations.
\begin{filenamelist}
\item[runtime/headers/flick/pres] These headers are specific to the
presentation implementation; they provide macros for things like handling
exceptions and memory management. This is also where any \SCML{} files
should be located.
\item[runtime/headers/flick/encode] These headers provide macros for encoding
and decoding data into and out of the message buffer.
\item[runtime/headers/flick/link] These headers provide macros for managing
the message buffers and adding any link level message data.
\end{filenamelist}
When the \ctype{mu_state} generates these macros it uses the \cidentifier{op}
flags and names for the presentation, encoding scheme, and protocol (link) to
determine the names of the macros. For example, the macro to encode an 8-bit
character in \CDR{} would be \cfunction{flick_cdr_encode_char8()}, and the
macro to decode would be \cfunction{flick_cdr_decode_char8()}. Unfortunately,
this approach can cause some problems because it restricts what parameters we
can pass to the macros, especially presentation specific macros which can vary
greatly.
Also note that much of Flick's flexibility is actually due to the
implementation of the macro calls. While the names change between back ends,
often the series of macro calls is very similar, and thus a significant amount
of the implementation comes from the definitions of the macros.
\subsection{client\_mu\_state and target\_mu\_state}
\label{subsec:BE:clientmustate and targetmustate}
The \ctype{client_mu_state} and \ctype{target_mu_state} C++ classes inherit
from the base \ctype{mu_state} class and describe how to marshal the client and
target object references, respectively. Most presentations do not have a
client reference, and most protocols do not have an explicit representation for
them. The client reference is necessary in the decomposed stub presentation,
and thus must be handled by the protocols and runtimes that support decomposed
stubs.
The reason these are special states is that the client and target references
are often encoded differently than other object references; for instance, they
may be placed at a known location within the message rather than encoded in the
midst of other parameter data. Since a single \ctype{mu_state} can only
specify one method for handling object references (e.g., the handling of an
arbitrary object reference parameter), the special client and server states
provide the mechanism in which the client and target references can be handled
specially and separately.
\subsection{mem\_mu\_state}
\label{subsec:BE:memmustate}
The \ctype{mem_mu_state} class is an extension of the basic \ctype{mu_state}
class, intended for use by typical back ends where parameters are marshaled (at
least partly) into variable-length memory buffers of some kind. It deals with
things like buffer management, alignment, endian conversion, etc.
For code optimization purposes, marshaled messages are logically divided into
\emph{globs}, then subdivided into \emph{chunks}.
A chunk is a sequence of bytes in the marshaled message whose length and
internal format is known. For example, a fixed-length array of bytes could be
one big chunk; an array with variably sized elements would not be a chunk, but
each individual element in that array could be. Chunks are used primarily for
optimization of data packing/unpacking code: once a chunk is started, no
alignment checks or pointer adjustments need to be done between successive
primitives in the chunk.
A glob is part of a message whose \emph{maximum possible length} is a
``smallish'' compile-time constant, even though the \emph{actual} length may
not be constant. For example, a variable-length array of bytes with a maximum
length of 32 bytes would be a good candidate for being lumped into a single
glob, whereas an array with variably sized elements and an unlimited length
would not be: instead each individual element of the array could be a separate
glob in that case. (The definition of ``smallish'' is defined by the back end:
each back end defines some maximum glob size, usually on the order of a few
kilobytes.) Globs are used to optimize marshaling buffer management: once
``enough'' buffer memory is allocated at the beginning of a glob, the
marshaling code within the glob can simply bump through with a pointer without
having to worry about buffer space again until the next glob.
\subsection{mu\_state\_arglist}
\label{subsec:BE:mustatearglist}
The \ctype{mu_state_arglist} class is used to help process some \PRESC{} nodes
by coalescing information from their children. For example, an allocation
context node has children representing the length, buffer pointer, and possibly
other attributes which need to be used together in order to do the correct
allocation. However, since this information is only known by the children, the
arglist provides a way of passing it back up to the parent (and/or subsequently
down to other siblings) so it can be used. The actual filling of the arglist
is taken care of by a \cidentifier{PRES_C_MAPPING_ARGUMENT} node on the path to
the child which will capture the current \CAST{} expression and type and store
it in a particular arglist and argument.
\begin{cprototypelist}
\item[mu_state_arglist(const char *name, mu_state_arglist *aparent = 0)]
Constructs an arglist with a name and optionally connected to a parent (the
new arglist must have a unique name (it cannot clash with a parent,
grandparent, etc.).
\item[~mu_state_arglist()] Destructs the arglist by freeing the list of
arguments and any other information.
\item[void add(const char *aname, const char *arg)] Adds an argument to the
named list.
\item[void remove(const char *aname, const char *arg)] Removes an argument
from the named list.
\item[int getargs(const char *aname, const char *arg, cast_expr *expr,
cast_type *type)] This will attempt to find the argument, \cidentifier{arg}
in the arglist, \cidentifier{aname}. If the argument is found, the
associated \CAST{} expression and type are returned with a nonzero result.
If the argument or arglist cannot be found, the method will return zero, and
\cidentifier{*expr} and \cidentifier{*type} will be set to \cliteral{NULL}.
\item[int setargs(const char *aname, const char *arg, cast_expr expr,
cast_type type)] Similar to \cfunction{getargs} except this will set the
value of argument. The return value is true if the argument was found and
set, zero otherwise.
\item[argument *findarg(const char *arg)] This is a private function used to
locate an argument inside a single list (it does not look at parents).
\end{cprototypelist}
\subsection{mu\_abort\_block}
\label{subsec:BE:muabortblock}
The \ctype{mu_abort_block} class is used for tracking any error handling code
in a stub. Thus, we're able to do a proper recovery from any possible errors
that occur during stub execution, such as a lack of memory or runtime error.
To accomplish this task the class provides functionality to add code for
handling an error, and then getting an ``abort label'' which the stub can jump
to during execution if the error occurs. The abort handling code is then
dumped at the end of blocks and then linked together with \cidentifier{goto}s.
Finally, the code is reduced to only contain those blocks that are reachable.
\begin{cprototypelist}
\item[void set_kind(int kind), int get_kind()] Set/get the kind
of this abort block. The possible kinds are:
\begin{cidentifierlist}
\item[MABK_NONE] No kind, this is illegal.
\item[MABK_THREAD] The abort block is a simple thread of
execution, one statement after another.
\item[MABK_CONTROL] The block has a unique control flow
amongst its children.
\item[MABK_CONTROL_IF] The block is an if statement, with the
only child representing the true branch.
\item[MABK_CONTROL_IF_ELSE] The block is an if/else statement,
where the child with an expression is the true arm and the one without is
the false arm.
\item[MABK_CONTROL_SWITCH] The block is a switch statement
with each child representing a case.
\end{cidentifierlist}
\item[void set_expr(cast_expr expr), cast_expr get_expr()]
Set/get the expression associated with this block. The expression is used
by the parent control block to make a link to this child (for example, the
expression used in a case).
\item[void set_reaper_label(cast_stmt reaper_label), cast_stmt
get_reaper_label()] Set/get the reaper label for this block. The reaper
label is the label to jump to at the end of the control flow for an abort
block.
\item[cast_stmt get_block_label()] Get the \ctype{cast_label}
associated with the abort block's \ctype{cast_block}. The label's statement
is actually the block, and is used for external references to the start of
the block. Any internal references will just be the first label in the
block.
\item[char *use_block_label()] Use the block label, this will increment the
use count in the \ctype{cast_label} and return the label string.
\item[void drop_block_label()] The opposite of \cfunction{use_block_label},
this will decrement the use count in the \ctype{cast_label}.
\item[void add_stmt(cast_stmt stmt)] Add a statement to the abort block.
\item[int stmt_count()] Return the number of statements in the
block. This is really meant for internal use to figure out if a child block
really does anything and needs to be linked to by the parent.
\item[void add_child(struct mu_abort_block *mab, int
connection)] Add a child to the abort block using a certain type of
connection, which can be:
\begin{cidentifierlist}
\item[MABF_INLINE] This indicates that the
child's \CAST{} block should be inlined directly inside the parents.
\item[MABF_OUT_OF_LINE] This indicates that the child's
\CAST{} block is located somewhere else in the code and a
\cidentifier{goto} should be used to reach the block.
\end{cidentifierlist}
\item[struct mu_abort_block *find_child(char *child_label)] This
will locate the child with the given label.
\item[cast_stmt get_current_label()] Returns the current label string.
\item[char *use_current_label()] This will return the string
corresponding to the current label name and increment the use count in the
\ctype{cast_label}.
\item[void grab_label(char *label)] Locates the given label name
and increments its use count.
\item[void drop_label(char *label)] Locates the given label name
and decrements its use count.
\item[void begin(), void end()] These perform initialization and
finalization around any additions of statements and children.
\item[int rollback(int has_path = 0)] This function will walk through the
abort block and all of its children trying to remove any dead code. The
\cidentifier{has_path} argument signifies whether or not a path begins with a
flow of control, and should almost always be left at zero when called
externally. Basically, this function goes through each statement and tries
to figure out if there is a path to that statement. If there is no path,
then it turns the statement to a \cidentifier{CAST_STMT_EMPTY}; otherwise the
statement is left alone. Determining the possibility of a path is done by
looking for any \ctype{cast_label}s that are used, a prior statement that has
a path, or a path from a parent.
\item[int rollback_block(cast_block *block, int start, int len,
int has_path)] This is a helper function for \cfunction{rollback}; this just
works on \ctype{cast_block}s. The return value indicates the possibility of
a control flow path.
\item[int rollback_stmt(cast_block *block, int pos, cast_stmt
curr_stmt, int has_path)] This is another helper function for
\cfunction{rollback}, and works on \ctype{cast_stmt}s. Again, the return
value indicates the possibility of a control flow path.
\item[void make_dispatch()] This is a private function used to
create any code for MABK\_CONTROL\_* kinds. Depending on the kind it will
produce the statements needed to do the test and dispatch to the correct
child block.
\end{cprototypelist}
\subsection{mu\_msg\_span}
\label{subsec:BE:mumsgspan}
The \ctype{mu_msg_span} class is used for putting buffer space checks into the
stub code so it does not try to decode something that is not there. The term
``span'' is used to describe a message segment of an exact size that can be
larger than a chunk, but not an approximation like a glob. The class is
used to describe each span in the message and join them together into a tree
which can then be reduced in a second pass. This reduction pass is used to
merge checks together and to lift them out of array loops, if possible.
For example, a union where each arm is the same size can be reduced to a single
check before unmarshaling the union, rather than a check for each arm.
Using the spans depends on the format of the message that is being unmarshaled
at the time. Normally, simple message segments are handled automatically by
piggy-backing on the chunk functions in the \ctype{mem_mu_state}. This allows
us to figure out how big a segment is, but we do not necessarily know how to
join it into the rest of the message. This merging is done by creating another
\ctype{mu_msg_span} which acts as a parent to a set of segments, and then
setting the kind of the span to one of the formats described below.
\begin{cprototypelist}
\item[void set_flags(int flags), int get_flags()] Set/get any
flags. Currently, the only flag is \cidentifier{MSF_ALIGN} which indicates
that the span follows an alignment so it cannot be absorbed by any previous
spans.
\item[void set_kind(int kind), int get_kind()] Set/get the kind.
The possible kinds are:
\begin{cidentifierlist}
\item[MSK_NONE] These contain the actual lengths
of a span and are usually added to one of the other kinds.
\item[MSK_SEQUENTIAL] These contain other spans which are
organized in a sequential fashion.
\item[MSK_UNION] These contain other spans which are organized
in a union, so each child is a different possibility in the union.
Usually, the children are \cidentifier{MSK_SEQUENTIAL} spans which then
contain the actual span lengths.
\item[MSK_ARRAY] These contain another span which indicates
the size of each element in the array, and the size of the array itself is
contained in the this object's \cidentifier{size_expr}.
\end{cidentifierlist}
\item[void set_block(cast_stmt block), cast_stmt get_block()]
Set/get the block where any checks should be added.
\item[void set_abort(struct mu_abort_block *mab), struct
mu_abort_block *get_abort()] Set/get the abort block to use for getting
labels.
\item[void grow(int size)] Grow the size of the span by a fixed size.
\item[void shrink(int size)] Shrink the size of the span by a fixed size.
\item[void set_size(cast_expr size)] Set the size of the span,
which may, or may not be fixed size. If this is a \cidentifier{MSK_ARRAY},
then this expression is used as the length of the array.
\item[void add_child(struct mu_msg_span *mms)] Add a child span
to this one.
\item[void begin(), void end()] These perform initialization and
finalization around any size modifications (growing, shrinking, adding
children).
\item[void drop()] Removes the check and drops the used abort label.
\item[void collapse()] This is called on the root span object to
go back through all of the children to optimize the sizes of the spans. For
sequential spans it will walk backwards through its children trying to absorb
the sizes into the previous span nodes, until it hits a variable sized node
which cannot be absorbed by the previous child. For unions, it will find the
minimum size of all the cases and use that as the size for the entire union.
For arrays, if the length is constant it will pull all the checks out of the
body of the loop and do a check at the start, otherwise it will just leave
the checks in the body. Any check statements that reduce to zero are changed
to \cidentifier{CAST_STMT_EMPTY}.
\item[void commit()] This is done after the call to collapse, it
basically does the final lock-down, any checks that have a size are set,
empty checks are dropped.
\item[static void set_be_name(const char *name)] This sets the
back end name that the spans will use when producing macro calls.
\end{cprototypelist}
\subsection{Implementing Presentation Functions}
\label{subsec:BE:Implementing Presentation Functions}
The presentation generator is able to create ``presentation functions'' which
have simple implementations and do not require optimization. However, the
presentation generator cannot provide the implementations since they may be
dependent on the runtime or other things specific to a back end. The current
solution is to store a simple description of the presentation function, a
semantically loaded string, in the presentation attributes tag lists. These
tag lists can then be processed by the back end to produce the needed code.
However, writing \cfunction{printf}s for each function can become complicated
and tedious, so the back end library provides a set of classes for
semi-automatically passing this work off to \SCML{}.
\begin{ctypelist}
\item[presentation_impl] This class is used to bind a tag in the
presentation attributes to a set of C++ functions and/or an \SCML{} macro.
The \SCML{} macro is determined by the \cidentifier{idl_type} and
\cidentifier{pres_type} which are nested scopes in \SCML{}, and finally the
macro is selected based on the string used to describe it in the presentation
generator.
\item[presentation_collection] This class walks over the tag lists in
the presentation attributes and then asks a set of \ctype{presentation_impl}
objects to implement whatever is described.
\end{ctypelist}
This approach is not always necessary since the \SCML{} interpreter can also be
called explicitly to execute macro's. See file prologue and epilogue handlers
in \filename{file_handlers.cc} for an example.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Specific Back Ends}
\label{sec:BE:Specific Back Ends}
The back end library is not able to produce working code by itself, so a
separate back end program must be created which provides its own functionality
in addition to the library, specializing the generic code generated by the
library into the specific code necessary to implement the encoding and
transport layers required by a specific protocol and runtime system. These
back ends are located in the \filename{c/pbe} directory and are all structured
very similarly.
\begin{itemize}
\item Fluke - Produces stubs for the Fluke operating system.
\item IIOP - Produces \CORBA{} \IIOP{} stubs for the Flick-provided C
runtime.
\item IIOPXX - Produces \CORBA{} \IIOP{} stubs for the TAO C++ runtime.
\item Khazana - Produces stubs for use with the Khazana distributed memory
system.
\item Mach3Mig - Produces stubs for use in the Mach~3 operating system using
MIG-compatible messages.
\item Sun - Produces \ONCRPC{} stubs that can replace those generated by
\rpcgen{}.
\item Trapeze - Produces stubs for the Flick-provided Trapeze based runtime
using either \XDR{} or \CDR{} encoding (based on the originating
presentation\footnote{Basing the encoding scheme on the originating
presentation is certainly not an ideal solution: the choice of \XDR{} versus
\CDR{} should be independent of which presentation is desired. See
Section~\ref{sec:BE:Summary and Comments} for a more detailed description of
the problem and proposed solution.}).
\end{itemize}
\subsection{The Basics}
\label{subsec:BE:The Basics}
The common tasks done in a back end are to create subclasses for the
\ctype{be_state} and the various \ctype{mu_state}s that implement the correct
behavior for the back end's encoding and runtime. Once these classes have been
filled out the stub writers are overridden to do some actual work. Coding
these stub generators is simply a matter of using the \ctype{mu_state}s to
generate \CAST{} blocks which are then bracketed by the appropriate runtime
code. Unfortunately, since all of this is relatively similar across all back
ends, it has become common practice to copy an existing back end and then
change all the names and \cfunction{printf}s to your needs. This results in a
fast start up time; however, this quickly turns into a maintenance nightmare.
Hopefully in the future the redundant code in the back ends will be
consolidated so that maintenance will be easier.
\subsection{Decomposed Stubs in IIOP and Khazana}
\label{subsec:BE:Decomposed Stubs in IIOP and Khazana}
Decomposed stub generation is an option of the presentation generator that
causes regular client stubs to be split into separate stubs (see
Section~\ref{subsec:PG:Decomposed Stubs Presentation} for more information).
Handling this kind of presentation is done simply through implementation of the
appropriate stub writers (for a detailed list, refer back to
Section~\ref{subsec:BE:Stub Generators}, assuming the runtime can support
it. They work basically the same as the regular client and server stubs, with
the functionality of the stubs split into separate functions. However, only the
\IIOP{} and Khazana back ends are currently able to handle this presentation.
\subsection{Presentation Implementation in IIOPXX}
\label{subsec:BE:Presentation Implementation in IIOPXX}
The IIOPXX back end is responsible for generating code specific to TAO, so
anything that is implementation dependent must be handled before outputting any
code. For example, a string inside of a structure needs to be of the
``TAO_Managed_String'' type and not a ``String_var'' like the PG will create
since it does not know the implementation. The solution is to use the
presentation implementation facilities to do any preprocessing. This type of
code has all been dumped in the file \filename{c/pbe/iiopxx/tao_impl.cc}.
Currently, this code ranges from generating \cidentifier{CORBA::TypeCode} to
modifying the structs and classes created by the presentation generator. Any
associated \SCML{} code is located in
\filename{runtime/headers/flick/pres/tao_*.scml}. Eventually, it would be nice
to organize the mess present in \filename{tao_impl.cc}, but exactly how best to
do it is unknown.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Summary and Comments}
\label{sec:BE:Summary and Comments}
The back end code generators are one of the most complex pieces of Flick,
mainly because of the number of choices that must (finally) be made. While the
current suite of back ends is impressive, particularly in their variety and
capabilities, there are a few design changes that might make them even more
flexible and useful. Following are a few ideas for improvement:
\begin{description}
\item[Reduce/Remove Dependence on Macros.]
%
Although a lot of flexibility arises through our use of macros, the macros
themselves can be hard to write and become a burden to maintain. Ideally,
the back end should generate \emph{code} and not a list of macro calls.
\item[Split the Encoding Mechanism, the Protocol, and the Transport
Mechanism.]
%
Ideally, these could all be independently chosen (and independent of the
presentation as well) for maximum flexibility. For example, it would be
conceivable to want \ONCRPC{}-style messages using \CDR{} encoding over a
Trapeze/Myrinet link. To some extent, the current design allows some
flexibility: the Trapeze back end and runtime support either \IIOP{}-style
messages with the \CDR{} encoding or \ONCRPC{}-style messages with the \XDR{}
encoding. However, most of the details are taken care of through macro magic
in the runtime header files, and the encoding/message format binding is still
fixed. It may be possible in some cases to change the encoding or transport
protocol simply by redefining the macros for a particular back end. However,
this is a rather daunting task and often requires at least some tweaks to the
back end code generator. In the future, it would be nice to have each aspect
of the generated code in some form of encapsulated module that could be
either statically linked in as part of the back end, or perhaps even chosen
at runtime by the user.
\item[Better Define the Separation of Presentation From Implementation.]
%
While it is clear how a \CORBA{} exception might be encoded using \IIOP{} and
\CDR{}, it is not defined how such a construct might be sent in an
\ONCRPC{}-style message. Some sort of conversion must be done between the
presentation and the encoding or message format layers to allow for the
abstract presentation entities to be encoded according to the link-layer
requirements. See Section~\ref{sec:Runtime:Logical Runtime and Header
Separation for Flick} for more discussion on this as it relates to the
runtime.
\end{description}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% End of file.
|