Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!wuarchive!uunet!overload!dillon From: dillon@overload.Berkeley.CA.US (Matthew Dillon) Newsgroups: comp.sys.amiga.programmer Subject: HYPER FUNCTIONALITY Message-ID: Date: 24 Apr 91 20:53:22 GMT References: <2407@swrinde.nde.swri.edu> Organization: Not an Organization Lines: 240 In article mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) writes: >In article <1991Apr22.071413.22219@agate.berkeley.edu> pete@violet.berkeley.edu (Pete Goodeve) writes: > In (18 Apr), > Mike (My Watch Has Windows) Meyer (mwm@pa.dec.com) writes: > > In article <1991Apr18.065847.8050@agate.berkeley.edu> pete@violet.berkeley.edu (Pete Goodeve) writes: > You SEE? ^^^ vvvv ... I KNEW it would happen... (:-)) > >What? You typed it in - and that's what it said. > ... My thoughts were that hyperfunctionality could be obtained through dynamically linked object modules. You would basically have a shared library that has the following calls: func = GetHyperFunc("display_bitmap") ... use function ... RelsHyperFunc(func) The scheme has the following advantages: (1) The object module associated with one or more functional names is independant of the calling code (i.e. can be third party), easily replacable and upgradable. (2) Programming overhead is minimal.. basically you just call GetHyperFunc(function_name) and it works. (3) The shared library searches for and finds the appropriate third party module containing the function and dynamically links it to the parent. (4) The module, being an object module, can reference other global variables and/or external routines (such as amiga.lib tags) that do not necessarily exist in the calling program. These external routines might in fact be other third party modules or .lib's (e.g. amiga.lib) that basically cause a recursive call to GetHyperFunc(). Thus, third party modules can depend on ALL OS calls being available to them. (5) STANDARD FUNCTIONS Third parties, the net, whoever, can define defacto standard functions such as 'IffToBitmap' with standardized arguments and standard return values, then others can improve on the initial offering by producing compatible modules that use the same call/return interface. In otherwords, a manual page for each function, like the autodocs. (6) FUNCTION ENTRY POINTS The shared library would require each third party module to have EITHER an assembly register based entry point for each interface function OR a stack based entry point. An assembly register entry point would begin: _asm_ A C stack entry point would begin: _stk_ THE LIBRARY WILL AUTOMATICALLY GENERATE CODE TAGS FOR PROGRAMS THAT REFERENCE THE _stk_ BASED FUNCTION IN A MODULE BUT WHERE THE MODULE ONLY DEFINES AN _asm_ BASED FUNCTION, AND VISE VERSA. In otherwords, the entry point type is INVISIBLE to any calling program. Other future entry point types can be defined. The associated .FD file that tells the library how to create a _stk_ interface from an _asm_ interface and vise versa MUST exist as const data in the object module based at a symbol named '_lib_fd', in otherwords, completely contained within the third party object module. The format will be extensible to allow more than _stk_ and _asm_ entry point types. (7) The procedure that generates code tags to convert the calling program's call format to the object module's call format is dynamically extensible as well. Procedures for _stk_ and _asm_ entry points (stk->asm and asm->stk) are built in to the shared library, but if new entry points are defined the shared library will itself search for third party functions that convert from one type to another. For example, a module that generates entry tags to convert from _fubar_ to _stk_ would be named: _stk_lib_convert_fubar_stk ^ \__________/ ^ ^ | | | convert to | | `--convert from | `- dedicated control name `- type of interface to the conversion procedure, must exist (using a _stk_ or _asm_ is safest since those are guarenteed to exist, being built into the shared library) The first key to all of this is 'THIRD PARTY' ... 'MIX AND MATCH' ... once you have mix-and-match capability at the USER LEVEL.. the user installs one third party module to do something but if some other third party comes up with a better one said user can install the better one without touching any of his application programs. The second key is complexity... through an extremely simple call you can interface to extremely complex modules, such as 'BitMapToPostScript' or something similar. The third key is in the dynamic linking capability. Note, I have written a shared library that does dynamic linking into a running program by searching for it's executable and symbol table, but in my opinion this particular capability -- linking to the calling process's symbols, is a BAD thing. In my opinion this is a loose, at least for now (dynamically linking object module's into the *calling* program and giving them access to the calling program's global's and other routines). First of all, RESIDENTed programs have no symbol table and no way to find the original executable. Secondly, the capability will lead to bad module implementations. Thirdly, there is no easy way to determine how to access a parent's existing variables.. for example, if the parent is using the small-data model (and there is no way to tell if it is without adding more complication), you are up the proverbial s*it creek. Also, the reentrantability of the third party modules is lost because you cannot assume the calling program will stick around (what happens if a second calling program wants to use the same module?) Finally, it adds incredible complexity to the shared library. It is MUCH easier for the shared library to do dynamic linking between OBJECT modules than it is to do dynamic linking to a pre-loaded and running executable whos symbol table might not be easily found. BUT DO NOT GET CONFUSED. I *AM* advocating dynamic linking BETWEEN third party modules. This is, in fact, how a module is able to call, say, OpenScreen()... it gets linked run time into another module that has the tag. You can even dynamically link into shared global variables that also exist in a given module. What I am NOT advocating is that the shared library be required to dynamically link an object module's unresolved references to the calling program's procedures. Not only that, but the interface specification still applies. If a module wants to call the C stack version of OpenScreen() but only a tag for the assembly register version exists, the shared library will generate the appropriate interface code to convert. The module itself would reference 'OpenScreen' normally, but a special default type would be encoded as a const data item, say called '_lib_deftype'. So, when all is said and done here is an example of a third party module, written in C: -------- cut -------- /* * default call type for calls that are not prepended with a type. */ const char lib_deftype[] = { "_stk_" }; /* * lib_fd defines the assembly and stack interface. Note that all * integer values in a stack interface are passed as longs. * * future extensions to other types or custom specifications may * be listed here using other ## constructions * * ##std standard (assembly & stack interface) * ##shared indicates the module functions are reentrant, otherwise * a duplicate of the module is made for each task calling * GetHyperFunc() for a function defined in this module. * * ## .. future constructions, any unknown construction is * ignored. * * note: var-args routines are supported with ..., but who knows * how we can standardize the call interface, mayabe just * require a stack only interface? */ const char lib_fd[] = { "##shared\n" "##std\n" "CalculateStuff(a,b,c)(D0,D1,D2)\n" "FuBarBletch(x)(A0)\n" }; /* * if no pre-tags are specified the lib_deftype[] is assumed as the * call format. If we were to specify a pretag, we would say something * like: asm_CalculateStuff(__asm register D0 a, register D1 b, ..) * etc, etc (not really SAS/C but you get the idea). * * This default action allows the source code to be easily portable, * especially of compiler options are used to automatically change * the default... for example, -mRR in DICE automatically registerizes * normal routines and the only change required to this source would * be to change lib_deftype[]. */ long CalculateStuff(a,b,c) long a, b, c; { } long FuBarBletch(x) long x; { ... OpenScreen() blah blah blah, etc... } -------- cut -------- That's it! That's the entire third party module! Easy to write, eh? So what do people think? Remember that libraries are also easy since they are simply object modules JOIN'd together. A third party could introduce a library of functions. Note that this specification does not impose any restrictions on what a module does or how it does it, you could easily encompass a streams system, message passing system, or other system simply by implementing them in your modules. You could, for example, provide the capability for AUTOMATIC cutting and pasting without the application even being aware of it! -Matt -- Matthew Dillon dillon@Overload.Berkeley.CA.US 891 Regal Rd. uunet.uu.net!overload!dillon Berkeley, Ca. 94708 USA