Templates, inlining, and why segment 1 fills up
When the CodeWarrior C++ compiler processes a class or function template, it saves an internal representation of the function in memory, later using this representation to create specific instances of the template when needed. For example,
template <typename T>
class Foo
{
};
doesn't generate any code. Code is only generated when a specific Foo<> is used, for example Foo<Int16>.
Normally, the compiler tries to generate inline forms of this code; when inlined, the code is expanded directly into the point where it is used. This gives the optimizer the chance to integrate the expanded code with the caller, resulting in smaller and more efficient programs.
However, inlining template bodies is a problem when debugging. Since there may be many instances of the inlined function in the application, the compiler cannot create a one-to-one mapping between lines of source code and locations in the object code. In fact, its a one-to-many-to-many situation, because a line of template code maps to a specific template instance, which then expands into a particular inlined instance of the template.
So, for debugging, you turn inlining off. However, this has another side effect. Inlined functions that are not generated into the caller code must have a special property: there must be only one copy of the function in the program. So, if we use Foo<int> in a.cpp and b.cpp but don't inline it, both a.cpp and b.cpp must call the same code.
To implement this, we generate a copy of the inline function for each C++ source file that uses it. However, we set a flag on the object code for the function telling the linker that it can be defined multiple times. This flag causes the linker to throw away all of the definitions but one and to link all the uses to that one definition.
Here is the problem. These definitions might come from multiple segments. You don't want to put the non-inlined code into segment 2 when its used by segment 1. Currently, the linker just puts anything flagged as multi-def in segment 1, since that one will always be available. However, if you make heavy use of the STL, you can generate way too much code to go into segment 1, giving you the problem you face now.
How do you solve this?
If you know the set of template instances you are using, you can explicitly instantiate them in source files. This is done through code like this.
template class Foo<int>;
This will generate all of the Foo<int> methods in the current source file without the multidef flag, so they will follow the current segmentation. Templates you don't explicitly instantiate will still go in segment 1. Also, templates should have the method bodies outside the class -- say
template <typename T>
class Foo
{
public:
T x;
Foo(const T &t);
};
template <typename T>
Foo<T>::Foo(const T &t)
{ x = t; }
rather than putting Foo's constructor definition inside the class body. This avoids getting the "inline" flag put on the function.
This is pretty confusing, I agree. However, the template features of C++ just don't work great on small-memory devices, especially ones with odd code-access schemes like the Palm.

Send feedback to combee@techwood.org
Copyright © 2004 Benjamin L. Combee
Palm OS is a registered trademark of PalmSource, Inc.
Metrowerks and CodeWarrior are registered trademarks of Metrowerks Inc.
The views expressed on this website/weblog are those of mine alone and do not necessarily reflect the views of PalmSource or Metrowerks.

qwertYAK / frobnovich
|