Accelerating Code Resources
Volume Number: 13
Issue Number: 6
Column Tag: Plugging In
Accelerating Code Resources and Import
by Fabrice Ferino, MDL Information Systems
How your plug-in can take advantage of the Power
Macintosh run-time architecture without telling the host
application
Import Libraries as Plug-ins
The traditional mechanism for the extension of a Macintosh application has been the
use of code resources. The Power Macintosh line of computers, and its associated
run-time environment, have enabled applications to provide a new way to implement
extensions as import libraries using the "universal plug-in" architecture described
in [4]. However, even if the application does not provide explicit support for the use
of import libraries as their extension mechanism, it is possible and advantageous for a
number of reasons to implement PowerPC native extensions as import libraries, and
to still package the complete plug-in a single file without contributing to the clutter of
the Extensions folder.
A Bit of History
For a long time, many of the successful Macintosh applications have provided a
mechanism to extend their functionality. In the 68k run-time environment, this
mechanism relied on the loading and executing of code resources. However, this type of
code has been more difficult to write than application code because of the limitations
imposed by the 68k run-time environment: no A5 world to reference the globals, the
limitation of the size of the code resource to less than 32K, and limit to a single
segment (because there is no jump table).
The majority of the modern development environments provide some ways to overcome
most of these limitations. The A4 register is cleverly hijacked to reference the globals
of the code resource, branch islands or the 68020 32-bit branching instructions are
used to allow code resource of a size larger than 32k. Still, writing a 68k code
resource requires more care and attention to detail than the common application code.
Readers interested in this area are directed to the excellent information available on
this subject. ([3], [5]).
The situation improved significantly with the arrival of the PowerPC run-time
architecture. With the availability of the Code Fragment Manager (CFM), an integral
part of the PowerPC system software, it became possible to implement extensions
using import libraries (colloquially known as shared libraries). Each import library
is a full-fledged MacOS citizen with its own global data space, and no size limits.
Additionally, if virtual memory is enabled and the import library is located on a device
that supports paging, the import library will be file-mapped and its code will not take
space in the heap of the host application. With all these advantages, many PowerPC
native applications (Code Warrior IDE, FreeHand, etc...) quickly adapted their plug-in
mechanism to use import libraries.
However, some applications still require their extensions to be code resources (some
of them have not be rewritten for the PowerPC architecture and others did not adopt
the new mechanism for diverse reasons). For this case, it is still possible to take
advantage of the increase of performance provided by the PowerPC family of
microprocessors by adopting an accelerated code resource. An accelerated code
resource runs only on Power Macintosh but can be called by both a 68k application or
a PowerPC application.
The format of an accelerated code resource is simple: this is a CFM code fragment
preceded by a routine descriptor. The first instruction in a routine descriptor is the
Mixed Mode Magic A-trap that triggers the mode switch necessary when the PowerPC
code resource is called by 68k code. But accelerated code resources, although they
provide some of the advantages of import libraries, still have some of the old
limitations (see [2] 1-39). Finally, accelerated code resources have a very annoying
characteristic: they have been difficult to debug with a source level debugger like the
Metrowerks Debugger. The Macintosh Debugger from Apple provides some support for
debugging memory-based code resource but it is still awkward. Source level debuggers
become confused because the CFM removes the connection information from its tables
after a memory based fragment has been prepared.
All these problems can be solved if most of the code of the extension resides in an
import library. The accelerated code resource then is just used as an interface between
the application and the import library. Figure 1 shows the general structure of a
68k code resource plug-in, of an accelerated code resource plug-in, and of a hybrid
accelerated code resource-import library.
Figure 1. Some architectures for plug-in code resources. Two other useful types not
represented here are safe fat code resources and import library based safe fat code
resources. The article focus on the build of the third type of code resources. RD:
routine descriptor.
Another advantage is that import libraries can have multiple entry points. If you need
to implement several code resources, each one providing an entry point to the
application, each of these code resources can call its own entry point in the import
library. This design makes the development of plug-ins that share code much easier
and offers the possibility for plug-ins to easily share data at run-time. This can be
done without having to allocate some data structure in the heap and devising a
mechanism to inform the plug-ins how to access this import data. The idea for this
plug-in architecture came when reading [2] 1-40:
"Note that a code fragment stored as an accelerated code resource can import both code
and data from an import library. The code and data in an import library do not move in
memory. As a result you can sidestep the restrictions on global data in an accelerated
code resource by putting the global data used by the accelerated code resource into an
import library.
To solve the debugging problem, this idea is extended to have most of the data and of the
code in an import library.
A Model Plug-in Application Based on Sprocket
An example host application is needed to demonstrate the implementation of import
library based accelerated code resources. Instead of selecting one of the real world
applications that do not take advantage of import libraries for their plug-in
mechanism, a modified version of the Sprocket framework that can load and execute
plug-ins has been implemented. With these extensions, Sprocket becomes a good model
of a 68k CFM unaware application. Note that the implementation is not claimed to be
the best one, but is simple and powerful enough to explore the concepts exposed in this
article. Using a 68k program makes the environment even more hostile for import
libraries.
One main difference with real world applications is that the application does not scan a
special plug-in folder but allows the user to load plug-ins by selecting the new Load