MOA Developer's Guide
MOA Interfaces | MOA Methods | MOA Types and Misc API

Director Xtra Development Kit: MOA Developer's Guide

MOA Development Issues


Introduction

This chapter address some issues about developing MOA on specific platforms and in specific development environments. It begins with a discussion of some internal issues with regard to MOA development. It then discusses the various compilers and development environments supported, noting specific details about setting up a compiler to develop MOA code. The discussion concludes with a reference section on the MOA for debugging macros.

MOA internals

This section addresses the programming languages available for MOA development and some internal issues with regard to method calls and memory footprints.

Programming languages

Both MOA clients and Xtras are intended be written in C or C++. The MOA Services Library itself is written in ANSI C, so that MOA can be implemented on platforms that don't support C++ compilers.

The MOA object system uses pointer-based allocation for internal data structures, since much of the library code is core, and MOA doesn't require a lot of memory in the first place. Note that all memory allocators will be configurable to allow for alternate memory managers (e.g., SmartHeap). Note also that every MOA application will provide Xtras with access to an implementation of the IMoaHandle interface for allocating relocatable memory.

Method calling overhead

The overhead for a MOA method call is identical to that of a C++ virtual function call. The calling technique is call-by-pointer, with an extra level of indirection. The performance impact is typically negligible for all but the tightest of inner loops. To look at some code comparisons, a typical direct C function call such as:

MyFunct();

compiles into the 68K assembly language call:

JSR 0x00000000 ; some address

A comparable MOA method call in C such as:

foo->lpVtbl->MyFunct(foo) /* C notation */

or in C++:

foo->MyFunct() /* C++ notation */

compiles into the assembly language call (again, 68K):

MOVE.L foo,-(A7) ; move first arg onto stack

MOVEA.L foo,A0 ; move foo into a register

MOVEA.L (A0),A0 ; get the vtable

MOVEA.L $000C(A0),A0 ; get the particular function to call

JSR (A0) ; call it

The last instruction is the equivalent to a standard C function call. You can optimize a method call down to a single instruction in a loop by getting the function address first, then calling it directly within the loop. For example:

void (*MyFunctProc)(void) = foo->lpVtbl->MyFunct;

while (tightloop) {

(*MyFunctProc)(foo);

}

In contrast, the speed cost of actually instantiating an interface is a bit more significant than creating a C++ object (you don't really want to do either one in speed-critical loops, naturally).

Memory overhead

The memory overhead for MOA objects and interface instances is:

* Overhead per object instance: 20 bytes + instance variables

* Overhead per interface instance: 8 bytes

It is most efficient to keep an object in memory without any interfaces instantiated other than IMoaUnknown. The IMoaUnknown interface is part of the base overhead of the object and can be used to instantiate any other interfaces at appropriate times. To ensure they are removed from memory, call Release() on interfaces you acquire through QueryInterface() when you are through using them.

Class and interface definitions also have some memory overhead. The figures for Mac MOA are (very) approximately:

* Overhead code per Xtra: ~1800 bytes

* Overhead per class definition: ~100 bytes

* Overhead per interface definition: ~400 bytes

Development Environments

On Windows, Visual C/C++ 2003 is fully supported by Adobe, while on the Macintosh, Apple XCode is fully supported. Support for other environments may be added in the future. Developers should contact Adobe about their specific needs if they require the use of other development environments.

In any environment, all structure-alignment must be carefully specified. MOA assumes "native" structure alignment in all cases: PPC code will assume PPC alignment, etc. However, it is strongly recommended that all structures should be long aligned in all cases, with explicit padding to force things to the proper boundary (i.e., structure definitions should not rely on compiler behavior to insert padding or correct alignment problems). This will make for easier portability, less risk of mismatched structures, and better performance on most modern machines.

MPW C promotes all types to long-size before passing them as parameters, while Think and Metrowerks do not. Microsoft's COM calling conventions require C calling conventions for interface methods, thus MOA API is exposed to this problem. For this reason, the arguments to all methods of all interfaces must be exactly 4 bytes in length. Smaller parameters should be passed as longs; larger parameters should be passed by pointer. Exception: 8-byte doubles (MoaDouble) may be passed by value. This rule applies to all interfaces defined by MOA and MOA-compliant applications.

Platform Notes

PPC Macintosh

Set your compiler to generate a shared library, file type 'Xtra', owner 'Xown'. PEF version info doesn't matter; you'll need to export the following symbols: "DllGetClassObject", "DllGetInterface", "DllGetClassForm", "DllCanUnloadNow", "ppcSetFileRef" (in Metrowerks, you can select "use #pragma" and the correct symbols will be exported). "DllGetClassInfo". You don't need an Initialize, Terminate or main entry point. Important: set structure alignment to PowerPC. Define the following preprocessor symbols for all files (using either a prefix file, compiler prefs, or command-line options):

#define MACINTOSH // compiling on Macintosh

You'll need the header files moaxtra.h, moastdif.h, and moatypes.h.

Windows 32-bit

In Win95, Win32s, and WinNT, the only compilers currently supported is MSVC2.x. Other compilers will be supported in the future.

Set your compiler to generate a large-model DLL. After producing the file, rename it to have the extension .x32 (rather than .dll). Currently, the windows projects define the following preprocessor symbols for all files:

#define _WINDOWS // compiling on Windows
#define WIN32 // compiling 32-bit Windows
The following symbol gets defined by other MOA headers if it is not defined in the project:
#define WINDOWS // compiling on Windows

Compiler Notes

MPW C

Support for MPW C/C++, which promotes all types to long-size before passing them as parameters, gives rise to the rule above requiring long argument types to all methods.

The MPW preprocessor is unable to handle the debugging macros discussed at the end of this chapter. MPW C also forces restrictions on A4 globals, which means some difficult programming for the uninitiated.

Debugging

Debugging PPC Xtras

On Power PC Macintoshes, when VM is off, MOA uses the call GetMemFragment() to load Xtras. However, the Metrowerks debugger won't properly debug code fragments loaded with this call. However, if you add a file in the Xtras folder named "_XtraDebugMode_", the call GetDiskFragment() is always used to load PPC Xtras, regardless of the VM state. This trick is intended for debugging purposes ONLY; your Xtras should be tested without this workaround in place before shipping.

Debugging Macros

Header file: moaxtra.h

The debugging macros defined in moaxtra.h may be useful for helping you develop Xtras. These macros can be added to and left in your code, since the behavior described here is only defined when you include the definition #define MOA_DEBUG in your Xtra code. Otherwise, they are defined as nil. As noted earlier, these macros can't be used with MPW C because of incompatibility with the C preprocessor.


MOA_ASSERT()

MOA_ASSERT(cond, msg)

cond Condition to test

msg Char * for the message to display if test is true

Displays the text msg only if the cond is true. On the Macintosh, this macro invokes debugstr(); on Windows, it invokes MessageBox().


MOA_CLOBBERMEM()

MOA_CLOBBERMEM(p, sz)

p Pointer to start of memory to clobber

sz Size of memory to clobber

Clobbers memory by writing bogus address values to the range from p to p + sz. This macro can force a failure in calls that otherwise find address-like values to jump to in the specified memory.


MOA_CLOBBERTEST()

MOA_CLOBBERTEST(p, msg)

p Pointer to memory to check

msg Char * for the message to display if memory is clobbered

Like MOA_ISCLOBBERED(), except displays the text msg if the memory has been clobbered. On the Macintosh, this macro invokes debugstr(); on Windows, it invokes MessageBox().


MOA_DEBUGSTR()

MOA_DEBUGSTR(msg)

msg String to display in the debugger

Use this macro to display the string x as your code executes. On the Macintosh, this macro invokes debugstr(); on Windows, it invokes MessageBox().


MOA_ISCLOBBERED()

MOA_ISCLOBBERED(p)

p Pointer to memory to check

Returns: TRUE if clobbered, FALSE otherwise

Checks the memory at address p to see if it has been clobbered.


Copyright © 1995-2007 Adobe Macromedia Software LLC, Inc.