[comp.sys.mac.programmer] XFCN/XCMD string in LSC C v3.0

oster@dewey.soe.berkeley.edu (David Phillip Oster) (04/09/89)

In article <12964@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle R. Horton) writes:
>     Using A4 as a base for global variables is a hack, anyway.  There
>are situations I know of which will invalidate A4, making your global
>variables useless.  (Dialog filter procs, for example.)

But Earle, that is exactly what the routines SetUpA4() and RestoreA4()
fix:

The compiler puts the data in the same resource as the code, after the
code. The routine RememberA0() stashes away A0, which on entry is a
pointer to the resource itself.  It staches it in the resource, but you
are going to be writing to the data area of the resource anyway, so
this is no worse.  SetUpA4() saves the old value of A4, and sets A4 to
point at the remembered value. After that, you have access to globals
until RestoreA4().  Things like dialog filter procs, and other
procedures that will be called by the operating system need to use
SetUpA4() RestoreA4() to get at the code resource's globals.  This is
no kludge, this is elegance compared to passing a pointer to a record
to every call.

One surprise: even if you have no globals, you still need to use
SetUpA4() and RestoreA4() to get at string constants and float
constants. Now that is a kludge!

earleh@eleazar.dartmouth.edu (Earle R. Horton) (04/09/89)

In article <28737@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP 
	(David Phillip Oster) writes:
>In article <12964@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu 
	(Earle R. Horton) writes:
>>     Using A4 as a base for global variables is a hack, anyway.  There
>>are situations I know of which will invalidate A4, making your global
>>variables useless.  (Dialog filter procs, for example.)

>But Earle, that is exactly what the routines SetUpA4() and RestoreA4()
>fix:
>
>The compiler puts the data in the same resource as the code, after the
>code. The routine RememberA0() stashes away A0, which on entry is a
>pointer to the resource itself.  It staches it in the resource, but you
>are going to be writing to the data area of the resource anyway, so
>this is no worse.  SetUpA4() saves the old value of A4, and sets A4 to
>point at the remembered value. After that, you have access to globals
>until RestoreA4().  Things like dialog filter procs, and other
>procedures that will be called by the operating system need to use
>SetUpA4() RestoreA4() to get at the code resource's globals.  This is
>no kludge, this is elegance compared to passing a pointer to a record
>to every call.

     Several problems exist with this approach.  The chief one is
writing to the code resource.  This is bad.  It can lead to strange
bugs on 68020 machines.

     Exactly where are the A4 values stored?  If in the code resource,
see previous paragraph.  If on the stack, see the latest TechNote on
SetUpA5() and RestoreA5().

     Saying that something is "no worse" is not as good as taking the
trouble to avoid the problem altogether.

     There are places where stand-alone code resources can implement
"global" variables, and not risk problems with processor caches.
Inside of the resource containing the code is not one of them.
Furthermore, these places vary from application to application, making
it impossible to do this right at the compiler level.  Sure, passing a
pointer to a data structure to every call may not be elegant, but it
is the only method which I can think of that:

     a)  Works for every conceivable application.
     b)  Does not write to the code resource sooner or later.

     The worst thing about development-system-specific tricks like
this is that they are not portable.  Remember portability?  When using
A4-relative data in a driver or code resource, you are perhaps saving
yourself some work, but you are writing code which will you can only
expect to be compatible with the development system you are using
right now.  The original poster wanted to convert some XCMDs from
LightSpeedD to MPW C.  He was in trouble because MPW C does not
provide A4-relative data.

     Coding for portability is being friendly to other programmers.
Using A4-relative data is not portable.

>One surprise: even if you have no globals, you still need to use
>SetUpA4() and RestoreA4() to get at string constants and float
>constants. Now that is a kludge!

     This is a compiler problem, for sure.  I recommend using Aztec C
as a fix to this particular problem.  Aztec C will put both string
constants and floating point constants in the code for you.

Earle R. Horton

Graduate Student.  Programmer.  God to my cats.

tim@hoptoad.uucp (Tim Maroney) (04/09/89)

In article <12968@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle
R. Horton) writes:
>     Several problems exist with this approach.  The chief one is
>writing to the code resource.  This is bad.  It can lead to strange
>bugs on 68020 machines.

Sorry, Earle, you're generally one of the better informed voices here
and one well worth reading, but you seem to be having a bad luck streak
this week.  There would only be a problem if the address where A4 is
stashed were executed.  That's the only way the address could find
its way into the instruction cache and cause problems: by being executed.
Since it's just being handled as data, there's no problem.

>     There are places where stand-alone code resources can implement
>"global" variables, and not risk problems with processor caches.
>Inside of the resource containing the code is not one of them.

The processor doesn't know resources from racehorses.  What it knows is
that there are lots of numbered memory locations, and it's ordered to
execute some of them.  These it may cache.  Others it won't, at least
not in the instruction cache.  Stashing data in code space is *not*
self-modifying code.

>Sure, passing a
>pointer to a data structure to every call may not be elegant, but it
>is the only method which I can think of that:
>
>     a)  Works for every conceivable application.
>     b)  Does not write to the code resource sooner or later.

Here we're pretty much in agreement.  In fact, I think it *is* elegant
to keep passing data structure handles through most levels of your
code, though if a routine only uses one or two fields of the data
structure, it's better just to pass those fields.  I've seen too many
programs ruined by indiscriminate use of globals, and I think data
structure arguments lead to far cleaner code in the long run.  However,
I still have not been able to write a serious program with no globals
at all (though I'd think you could do it in a small code chunk like an
XCMD) and mucking about with globals registers remains a neccessary
evil in the real world.  Globals should be minimized as a matter of
good programming practice, but it's unrealistic to expect them to
vanish altogether from any large piece of code.

One more note.  This whole thing got started because of a discussion of
string constants.  Uh, guys, you're not supposed to be using those on
the Mac, ya know.  Sure it would be nice if every compiler let you put
them in code space, but for internationalization, you're supposed to
put all of them into 'STR ' and 'STR#' resources.  I have not found
this to be a real burden as long as you run MultiFinder; you can use
ResEdit while your development system stays up.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Something was badly amiss with the spiritual life of the planet, thought
 Gibreel Farishta.  Too many demons inside people claiming to believe in
 God." -- Salman Rushdie, THE SATANIC VERSES

earleh@eleazar.dartmouth.edu (Earle R. Horton) (04/10/89)

In article <6944@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>In article <12968@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu 
	(Earle R. Horton) writes:
>>     Several problems exist with this approach.  The chief one is
>>writing to the code resource.  This is bad.  It can lead to strange
>>bugs on 68020 machines.
>
>Sorry, Earle, you're generally one of the better informed voices here
>and one well worth reading, but you seem to be having a bad luck streak
>this week.  There would only be a problem if the address where A4 is
>stashed were executed.  That's the only way the address could find
>its way into the instruction cache and cause problems: by being executed.
>Since it's just being handled as data, there's no problem.

>...Stashing data in code space is *not* self-modifying code.

  The second group is code that changes the block that the code is
  stored in.  Keeping variables in the CODE segment itself is an example
  of this.  This is uncommon with high-level languages, but it is easy
  to do in assembly language (using the DC directive).  Variables
  defined in the code itself should be read-only (constants).  Code that
  modifies itself has signed a tacit agreement that says "I'm being
  tricky, if I die, I'll revise it."
  ...
  If you choose to abuse, you also agree to personal visits from the
  Apple thought police, who will be hired as soon as we find out.

     Technical Note 117, "Compatibility: Why and How." Bo3b Johnson.

     Well, Apple thinks that this *is* self-modifying code.  To be
honest, I don't know if this kind of thing gets into the code cache or
not, but it might someday.  If you want to write straight-up code
then writing to logical code blocks is to be avoided.  If you want to
write tricky code, then you may do so.  The best advice seems to be to
avoid being tricky if you want your programs to last.

     Programming the Macintosh is difficult.  Relying on a compiler
which uses questionable tricks to make that task appear easier is
risky at best.  MPW compilers do not implement global read/write
variables for non-application code resources, presumably because Apple
has not found a safe place to stash the base register.

     Conclusion:  Using global variables in non-application code
resources is at present risky business.  Even though the compiler
writer says "Go ahead and do it," the choice to be tricky or not is
yours.
Earle R. Horton

Graduate Student.  Programmer.  God to my cats.

dg@okra.sybase.com (David Gould) (04/10/89)

In article <6944@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>In article <12968@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle
>R. Horton) writes:
>>     Several problems exist with this approach.  The chief one is
>>writing to the code resource.  This is bad.  It can lead to strange
>>bugs on 68020 machines.
>
>Sorry, Earle, you're generally one of the better informed voices here
>and one well worth reading, but you seem to be having a bad luck streak
>this week.  There would only be a problem if the address where A4 is
>stashed were executed.  That's the only way the address could find
>its way into the instruction cache and cause problems: by being executed.
>Since it's just being handled as data, there's no problem.
 [ other cogent discussion omitted...]
>Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim

Sorry, Tim, but Earle is right, even if for the wrong reasons.  In a protected
or virtual memory environment, it is very common to use the MMU to map 'pure'
code and constant data pages as read only.

 - Pure code and data pages can be shared by all programs without using extra
   physical memory.
 - The paging mechanism knowns in advance that pure pages will never be written
   to the pagefile, so it doesn't need pagefile space for them.
 - It helps system reliability to have OS enforced memory access protection.
   This helps catch pointer runaways and other system subversion (eg virii).

It is quite likely that in Apple's future multitasking virtual memory system
that code resources will be mapped read only.  Thus, under system N.0 (for some
large N) any code that writes on code resources will break. 

					...dg
 David Gould                           Sybase, Incorporated      (415) 596-3414
 sybase!dg@sun.com                     6475 Christie Ave.  Emeryville, CA 94608
 {sun,lll-tis,pyramid,pacbell}!sybase!dg

tim@hoptoad.uucp (Tim Maroney) (04/11/89)

Recap to avoid excessive quotation:  We're discussing the problems of using
globals in non-application code, specifically with respect to stashing
globals in code space and providing globals in non-apps under MPW C.

In article <12970@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle
R. Horton) writes:
>
>     Well, Apple thinks that this *is* self-modifying code.  To be
>honest, I don't know if this kind of thing gets into the code cache or
>not, but it might someday.  If you want to write straight-up code
>then writing to logical code blocks is to be avoided.  If you want to
>write tricky code, then you may do so.  The best advice seems to be to
>avoid being tricky if you want your programs to last.

("This" being putting globals in code space.)  In my opinion, the Tech
Note is being loose in its definitions.  Most people reserve the phrase
"self-modifying code" for software that rewrites its INSTRUCTIONS.  If
you review the Tech Note, you will also find that no rationale is given
for not putting globals into code space; he just says that since it's
"self-modifying code" (it isn't) it's tricky and shoudl be avoided.

The fact remains that such non-executable and non-executed data is not
stored in the instruction cache and is very unlikely to be on any
future processor.  Motorola understands that its processors need to
make the minimum of assumptions about the operating environment, and
when it has an approach in place that works in every conceivable
situation (only caching instructions that it has executed, and only
consulting the instruction cache during instruction fetch) it is
inconceivable to me that they would change it to a less general
appraoch that has no apparent advantages.

It's always best to avoid trickiness.  I don't consider this technique
particularly tricky.  I do think the Tech Note you cited was employing
a tricky definition, however.

>     Programming the Macintosh is difficult.  Relying on a compiler
>which uses questionable tricks to make that task appear easier is
>risky at best.  MPW compilers do not implement global read/write
>variables for non-application code resources, presumably because Apple
>has not found a safe place to stash the base register.

It doesn't implement them in the sense of holding your hand at every
step of the process.  However, it doesn't put up much of a fuss if you
decide to do it yourself.  The compiler and linker will happily churn
out a consistent set of offsets from A5.  As for where to stash the
data register, newer Technical Notes explicitly state that if you must,
you can stash your globals register in code-relative space.  (This is
primarily for interrupt-driven code, but it works fine for maintaining
your own globals register.)

>     Conclusion:  Using global variables in non-application code
>resources is at present risky business.  Even though the compiler
>writer says "Go ahead and do it," the choice to be tricky or not is
>yours.

Conclusion based on what?  At present, it's perfectly safe.  In the
future, it is remotely possible that this culd break if Motorola does
something tremendously stupid, or if Apple implements a memory-protected
OS that destroys many of its major third-party products.

As I've said, it is practically impossible to write medium-and-larger
programs that completely eschew globals.  Something of the magnitude of
TOPS never could.  TOPS is a user-level protocol; programmer protocols
like TCP also have a need to maintain connection tables and access them
when a packet comes in.  It might seem that a protocol could avoid
globals by letting the protocol caller maintain a copy of a connection
record, but the software needs to access the tables on the fly, not
just when the caller accesses the protocol implementation.  And so on.

A small code resource like a definition routine or XCMD can probably
get by with no globals, and ought to do so if possible.  But as I said
previously, globals are a neccessary evil in modern programming
languages.  Cavalier dismissals of their necessity are not too likely
to convince someone who has been involved in large projects and lots of
large code resources.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"The above opinions and suggestions have absolutely nothing to do with
 the little, fat man putting crisp, $100 bills in my pocket."
    -- Alan Vymetalik

mjm@eleazar.dartmouth.edu (Michael McClemen) (04/11/89)

If (as I read in current trade publications) the 68040 (presumably the wave
of the future as far as such things go) has separate data and instruction
caches, why would storing data in code space be a problem for a program running
on that processor?  Being rather ignorant about low-level architecture, my
initial perception is that instruction fetches would use one cache, while data
fetches would use the other.  Now, since you obviously have to be able to write
to data-cached locations (a write-through cache, correct?) why wouldn't data
fetches from an address also coincidentally stored in the instruction cache go
through the data cache and not mind that that memory cell had been written to?
This is quite a different matter from self-modifying code, where subsequent
fetches from a modified location go through a read-only cache.

If there is a flaw in my understanding, I would be grateful if someone would
explain this business more throughly; I have had the question for quite a while
now.

-- Michael McClennen

thecloud@dhw68k.cts.com (Ken McLeod) (04/11/89)

In article <6944@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>In article <12968@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle
>R. Horton) writes:
>>     Several problems exist with this approach.  The chief one is
>>writing to the code resource.  This is bad.  It can lead to strange
>>bugs on 68020 machines.
>>
>>     There are places where stand-alone code resources can implement
>>"global" variables, and not risk problems with processor caches.
>>Inside of the resource containing the code is not one of them.

>The processor doesn't know resources from racehorses.  What it knows is
>that there are lots of numbered memory locations, and it's ordered to
>execute some of them.  These it may cache.  Others it won't, at least
>not in the instruction cache.  Stashing data in code space is *not*
>self-modifying code.

  What happens on 68030 machines, which have both instruction and data
caches? I've written an INIT in LSC, using A4-relative global data which
I update (read: write to) when certain parameters are changed by the user
through a 'cdev' interface to my patch. As far as I can tell, when my INIT
code goes to fetch the value stored in one of my 'globals', the processor
will use the value in the data cache if it exists there; otherwise, it will
get it from the actual address. But won't altering data at a particular
address cause the cached 'copy' of the data to become invalid, and force
the processor to re-read the data? Or will the "old" value stored in the
cache stay there, and continue to be used? Perhaps there's a way to flush
the data cache? How exactly does processor data caching work?

 (Insert "inquiring minds..." cliche here)


-- 
==========     .......     =============================================
Ken McLeod    :.     .:    UUCP: ...{spsd,zardoz,felix}!dhw68k!thecloud
==========   :::.. ..:::   INTERNET: thecloud@dhw68k.cts.com
                ////       =============================================

tim@hoptoad.uucp (Tim Maroney) (04/12/89)

In article <3756@sybase.sybase.com> dg@okra.UUCP (David Gould) writes:
>Sorry, Tim, but Earle is right, even if for the wrong reasons.  In a protected
>or virtual memory environment, it is very common to use the MMU to map 'pure'
>code and constant data pages as read only.

Sure, and I expect that when Apple comes out with a memory protected
OS, probably in 1990, application CODE resources and possibly some
definition routines (WDEFs, MDEFs, CDEFs, LDEFs) will be mapped into
read-only space.  It is also possible that this will be done with DRVRs
and CDEVs, though I doubt it -- too many of them stash things in code
space so they can access them at the interrupt level without wasting
time searching through system queues.  Possibly even XCMDs/XFCNs will
be mapped read-only.

However, there are some resources that won't ever be marked as
read-only unless they conspire to do it themselves, and that's the kind
I usually write.  For instance, INITs that install themselves in the
system heap or BufPtr and patch traps won't be marked read-only because
the system doesn't know what's going on -- as far as it's concerned,
this is data.  Once this kind of code is installed, it's not even a
resource any more.  Or, utility libraries that provide database services
or implement a help system, stored as a code resource with a "routine
selector" type dispatch routine at the start of the resource.  These
may remain resources, but of a non-standard type that the system has
no way of recognizing.

>It is quite likely that in Apple's future multitasking virtual memory system
>that code resources will be mapped read only.  Thus, under system N.0 (for some
>large N) any code that writes on code resources will break. 

Not "any", for the reasons cited above.  Some.

Furthermore, I expect that Apple will have to provide a way to override
this protection.  For instance, suppose that your application
implements a network protocol that installs a socket listener or
protocol handler.  There's no way around it -- that listener *must*
stash its globals register (at least) in code space.  If it doesn't, it
has no way to communicate packets received to the rest of the
application.  Furthermore, it must be linked with the rest of the
application, not as a separate code resource, because otherwise it
can't know what offset to use for the "packets received queue" global.
Other code that can't get around running at the interrupt level will
also need to use this trick.

Apple may or may not do this in a backwards-compatible way -- I hope
they do.  MultiFinder is backwards compatible because "no MultiFinder
resource" means "not MultiFinder friendly".  The same could be
accomplished by a resource indicating "make my code resources
read-only".  If it's missing, they're read-write; otherwise, they're
read-only.  The same approach could be used with CDEVs and DRVRs, using
an owned "make me read-only" resource.  Or Apple could just use the
reserved resource flags bit for that purpose (bit 0; see IM I-111.)
Nobody's got it set now, so this would work correctly.

On the other hand, a clean but incompatible way to do this would be to
provide a new trap that temporarily turns off memory protection, or a
version of BlockMove that ignores memory protection.  Notice that the
application socket listener only needs to write into code space once.
This could easily be accomplished using these traps, albeit breaking
existing code in the process.  Apple's usually pretty good about
compatibility, since computers get sold by their software base, so I
expect they will probably use some variant on the "read-only resource",
rather than requiring calls to new traps.

So why don't older OS's like UNIX have to do this?  Typically, they use
absolute globals rather than globals relative to an offset, because
they had some form of MMU built in from the start.  If the Mac used
this approach, then the issue would be irrelevant -- the socket
listener would just stash it at global location 0x2500 or something.
The OS is also statically linked -- the system maintainer has to relink
the system whenever something is added, barring special hacks for
run-time drivers that have been made in some UNIXes this decade.

If Apple had done this to globals, they could never have expanded the
system heap, nor provided Switcher or MultiFinder, on their existing
machines.  With register-relative globals, relocatability does not
require an MMU.  Good design decision for a low-end computer.

Semi-related PS:  John Gilmore wrote to inform me that non-executed
data *can* find its way into the instruction cache because of prefetch.
However, since the cache is only consulted during instruction fetch,
not data fetch, there's still not a problem with PC-relative data.
The instruction cache may have an invalid copy, but the processor
won't look there unless it's executing that location.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Mere opinion without supporting argument is no more than the American
 Bandstand school of literary evaluation."  -- Tom Maddox

tim@hoptoad.uucp (Tim Maroney) (04/14/89)

In article <22027@dhw68k.cts.com> thecloud@dhw68k.cts.com (Ken McLeod) writes:
>  What happens on 68030 machines, which have both instruction and data
>caches?

Simple; when you change the value at an address, the value in the data
cache changes.  Data caching would be pretty useless otherwise, if you
think about it.  What use would there be in having a data cache that
didn't stay synched with RAM?  This is not a problem.

(Note -- I don't have a 68030 manual, and it's possible that instead of
immediately updating the cache value, it just invalidates it on write.
As far as the programmer is concerned, the effect is the same.)
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Every institution I've ever been associated with has tried to screw me."
	-- Stephen Wolfram

ech@pegasus.ATT.COM (Edward C Horvath) (04/14/89)

From article <6944@hoptoad.uucp>, by tim@hoptoad.uucp (Tim Maroney):

> One more note.  This whole thing got started because of a discussion of
> string constants.  Uh, guys, you're not supposed to be using those on
> the Mac, ya know.  Sure it would be nice if every compiler let you put
> them in code space, but for internationalization, you're supposed to
> put all of them into 'STR ' and 'STR#' resources.  I have not found
> this to be a real burden as long as you run MultiFinder; you can use
> ResEdit while your development system stays up.

If all you develop are applications, which own all resource IDs from
128 through 2^15-1, or DRVRs (each which owns 32 IDs of every conceivable
resource) or one of the other "blessed" code types, this is a reasonable
approach.  What STR and STR# resource IDs should an XCMD use?  Or should
I use GetNamedResource and HOPE nobody else uses a STR# named "godzilla"?

I'm not challenging the value of Tim's approach where it's cleanly
applicable, but what to do where it isn't?  DTS?

=Ned Horvath=

ech@pegasus.ATT.COM (Edward C Horvath) (04/14/89)

In article <6944@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>The processor doesn't know resources from racehorses.  What it knows is
>that there are lots of numbered memory locations, and it's ordered to
>execute some of them.  These it may cache.  Others it won't, at least
>not in the instruction cache.  Stashing data in code space is *not*
>self-modifying code.

From article <22027@dhw68k.cts.com>, by thecloud@dhw68k.cts.com (Ken McLeod):
>   What happens on 68030 machines, which have both instruction and data
> caches?

What SHOULD happen, naturally!  Listen carefully, and re-read as necessary:
The PC is used to fetch instructions, from the cache if there's a hit, from
RAM otherwise.  ALL other memory references are to/from the data cache if
there is one, and all writes to the data cache are write-thru.

Thus, for example, when you save an A5 or A4 or whathaveyou value, it is
written to the data cache (if any) and RAM.

This is so simple that it is hard to screw up.

That doesn't mean that, at some point, you won't run under an OS that
write-protects what it believes to be code.  When that happens, code from
Aztec C or MPW C with the -b will still be fine: only constants (which you
aren't going to modify, right?) are in codespace, and they can be write
protected.  An attempt to store an Ax reg in codespace will cause a memory
exception and termination with extreme prejudice.  But, as Tim Maroney
observed, there are things like IO Completion routines that CAN'T operate
any other way under the present Mac regime: they MUST store the global
base reg in a pc-relative place.

I suspect that Tim has correctly predicted the future as well: there will
be a bit in the BNDL or SIZE resource that says the app will deal properly
with being loaded at (virtual) address 0 (like the Unix model).  Since
data is always at the same (virtual) address with this model, all that
remains is for the app to be able to tell how it's loaded, say by a flag
in SysEnvirons.

=Ned Horvath=

tim@hoptoad.uucp (Tim Maroney) (04/14/89)

In article <2784@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes:
>If all you develop are applications, which own all resource IDs from
>128 through 2^15-1, or DRVRs (each which owns 32 IDs of every conceivable
>resource) or one of the other "blessed" code types, this is a reasonable
>approach.  What STR and STR# resource IDs should an XCMD use?  Or should
>I use GetNamedResource and HOPE nobody else uses a STR# named "godzilla"?

Very interesting point.  How about just saying that you use the same
resource id as the XCMD uses?  The programmer ought to be able to find
some suitable ID for both an XCMD and a STR# (and you shouldn't need
more than one of the latter).  The XCMD can discover its own id by
getting a pointer to its first address (either the address of the entry
point routine, or the A0 that the default LSC header passes you), doing
a RecoverHandle, then doing a GetResInfo.

If you use GetNamedResource, you're back to using strings in your code
-- while you're still easier to internationalize, the technical
problems with strings in code resources remain.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"The government of the United States is not, in any sense, founded
 on the Christian religion." -- George Washington

alexis@ccnysci.UUCP (Alexis Rosen) (04/14/89)

In article <6944@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>In article <12968@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle
>R. Horton) writes:
>>     Several problems exist with this approach.  The chief one is
>>writing to the code resource.  This is bad.  It can lead to strange
>>bugs on 68020 machines.
>
>[...]  There would only be a problem if the address where A4 is
>stashed were executed.  That's the only way the address could find
>its way into the instruction cache and cause problems: by being executed.
>Since it's just being handled as data, there's no problem.

This was my initial reaction as well. But I'm not so sure.

First of all, is code stashed in the cache on a byte-by-byte basis? Maybe,
in the 020/030, it is. I'm not sure. (I can't see it reading ahead in
32-word chunks, really. Too slow.)

But in the 040 there are 4K bytes of instruction cache. Does the CPU tag
each word? If not, data could wind up being sucked into the cache along
with instructions. Not much, but some.

On the other hand, this probably wouldn't affect things anyway, since there
wouldn't be a cache hit in the i-cache when it's looking for data, would
there?

confusion reigns...

---
Alexis Rosen
alexis@ccnysci.{uucp,bitnet}

p.s. Why haven't there been any discussions of the '040, either here or in
comp.arch? Wasn't the information announced enough to start a half-dozen
flame wars?

alexis@ccnysci.UUCP (Alexis Rosen) (04/14/89)

Perhaps I'm being dense (it's 5AM), but why can't compilers just see that
they're creating a stand-alone resource and put the "globals" in a stack
frame?

---
Alexis Rosen
alexis@ccnysci.{uucp,bitnet}

duggie@Jessica.stanford.edu (Doug Felt) (04/15/89)

The problem with using the resource id of the XCMD/XFCN resource as
the key to a corresponding STR# (or other) resource is that generally
when you copy resources the resource id gets reassigned.  Thus if you
distribute an XCMD in a stack with an "install" option you need an
installer XCMD that 1) lets you detect id conflicts and 2) lets you
assign ids explicitly.  The most common installers don't, and I had to
write my own in order to handle this problem.

If you don't plan on letting the user copy the XCMD then you have
complete control over the resource numbering and naming, so can use
whatever scheme suits you (as long as you use the 1 level deep
resource manager calls).

Multiple resources are also a problem if you plan on letting the user
switch stacks, which causes resource files to be closed.  You must
take care not to create data structures containing resource handles
that might persist over the closing of a stack.  Most XCMD's don't
do this so few people hit this problem.

I say go ahead and use embedded strings.  Hypercard is not really
script-manager friendly, and many stacks do lots of string munging
that is not fully language-independent.  When you get right down to
it, XCMDs are basically a hack. Lets not worry too hard about whether
we're following all the compatibility rules.

Doug Felt
Courseware Authoring Tools Project

ech@pegasus.ATT.COM (Edward C Horvath) (04/15/89)

From article <1583@ccnysci.UUCP>, by alexis@ccnysci.UUCP (Alexis Rosen):

> Perhaps I'm being dense (it's 5AM), but why can't compilers just see that
> they're creating a stand-alone resource and put the "globals" in a stack
> frame?

You're not dense: the easiest way for a pascal programmer to end-run the
globals problem is to declare a "main" PROCEDURE and nest all the
subroutines within it.  If the codeRes is small enough, no worries.

C programmers, lacking nested procedures, are underwhelmed by this
solution.  Thus Aztec C and LSC both provide for globals in code resources.
MPW C does not.

Hmm, I wonder who drives the MPW bus...

=Ned Horvath=

bayes@hpfcdc.HP.COM (Scott Bayes) (04/15/89)

As far as I know the cache-line is 4 longwords in the 68030 d and i-caches.
This is 128 bits, and is aligned to quad-longword boundaries. If there's a
cache miss, the address you wanted is loaded first, then the remaining
data in the cache line is loaded into the cache while the CPU messes with the
data just loaded. Of course, all flushes also happen on quad-longword
boundaries as well. You really want a 32-bit wide data bus in the machine
to take advantage of this.

Scott Bayes

pratt@boulder.Colorado.EDU (Jonathan Pratt) (04/15/89)

In article <2788@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes:
>You're not dense: the easiest way for a pascal programmer to end-run the
>globals problem is to declare a "main" PROCEDURE and nest all the
>subroutines within it.
>
I just wanted to point out that C programmers can emulate this nested
globals behavior by doing manually what the Pascal compiler does auto-
magically: simply define the globals as a struct var in the procedure
designated as "main" and pass a pointer to this struct to each "nested"
procedure.  Pascal does this with hidden arguments.  Yes, it does get
a bit ugly if the nesting grows deep.  I noticed that LSP does a pretty
nice job of this for single nesting;  Address register A4 picks up the
hidden globals pointer, so there isn't much overhead.

Jonathan

/* Jonathan Pratt          Internet: pratt@boulder.colorado.edu     *
 * Campus Box 525              uucp: ..!{ncar|nbires}!boulder!pratt *
 * University of Colorado                                           *
 * Boulder, CO 80309          Phone: (303) 492-4293                 */

paul@taniwha.UUCP (Paul Campbell) (04/16/89)

In article <2786@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes:
>
>What SHOULD happen, naturally!  Listen carefully, and re-read as necessary:
>The PC is used to fetch instructions, from the cache if there's a hit, from
>RAM otherwise.  ALL other memory references are to/from the data cache if
>there is one, and all writes to the data cache are write-thru.
>
>This is so simple that it is hard to screw up.

well not quite that simple, the tags in the caches are 'virtual' addresses,
the MacOS (24 bit) aliases the same memory locations with different
addresses (yes .... the Handle tags in the high byte! :-) on the '030
they get away with this in the data cache (it doesn't matter in the
instruction cache because you don't write to it) by setting the WA bit in
the cache control register.

They also have to do an instruction cache invalidate when doing a _LoadSeg.

	Paul

-- 
Paul Campbell
Taniwha Systems Design			UUCP:		..!mtxinu!taniwha!paul 
Oakland CA				AppleLink:	D3213

tim@hoptoad.uucp (Tim Maroney) (04/17/89)

In article <1567@Portia.Stanford.EDU> duggie@Jessica.stanford.edu (Doug Felt)
writes:
>The problem with using the resource id of the XCMD/XFCN resource as
>the key to a corresponding STR# (or other) resource is that generally
>when you copy resources the resource id gets reassigned.  Thus if you
>distribute an XCMD in a stack with an "install" option you need an
>installer XCMD that 1) lets you detect id conflicts and 2) lets you
>assign ids explicitly.  The most common installers don't, and I had to
>write my own in order to handle this problem.

Well, but, a "user" should never see an XCMD.  It's a developer tool
which is (or should be) only visible to the highest level of HC users,
those who've clicked user level scripting.  Once you get to that
level, there shoudn't be any problem with instructing the developer
to use ResEdit.  You don't need to idiot-proof things by providing
an HC installer.

>I say go ahead and use embedded strings.  Hypercard is not really
>script-manager friendly, and many stacks do lots of string munging
>that is not fully language-independent.  When you get right down to
>it, XCMDs are basically a hack. Lets not worry too hard about whether
>we're following all the compatibility rules.

Gag!  Choke!

The last sentence is too obviously screwy to bother refuting, but there
is an interesting issue earlier on.  You can be internationalizable
without being Script Manager friendly -- there are really two levels of
international portability.  One is when you're compatible with other
Indo-European languages that use one-byte-per-character alphabets and
separate words using spaces; the other is where you're compatible with
any language that can be crammed into the Script Manager.  The claimed
HC incompatibility with the Script Manager may be real, but on the
other hand, HC *is* pretty Europe-friendly.  Any developer who doesn't
want to break this would be well advised to use separate strings.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"Conversion, fastidious Goddess, loves blood better than brick, and feasts
 most subtly on the human will." - Virginia Woolf, "Mrs. Dalloway"

duggie@Jessica.stanford.edu (Doug Felt) (04/17/89)

In article <7020@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>In article <1567@Portia.Stanford.EDU> duggie@Jessica.stanford.edu (Doug Felt)
>writes:
>>The problem with using the resource id of the XCMD/XFCN resource as
>>the key to a corresponding STR# (or other) resource is that generally
>>when you copy resources the resource id gets reassigned.  Thus if you
>>...
>
>Well, but, a "user" should never see an XCMD.  It's a developer tool
>which is (or should be) only visible to the highest level of HC users,
>those who've clicked user level scripting.  Once you get to that
>level, there shoudn't be any problem with instructing the developer
>to use ResEdit.  You don't need to idiot-proof things by providing
>an HC installer.

I disagree.  First, there are users who do no appreciable amount of
scripting but who may still create simple stacks for their own use, by
cutting and pasting buttons, laying out fields, and the like.  They
interact with XCMDs by pushing buttons.  A simple example would be an
"Open" button which brings up the open file dialog and lets the user
launch an application.  A user who does no scripting, and does not
know how to use or even own Resedit, may yet wish to have this in her
or his Home or other stack.  An "Install" button is the best means of
getting it there.  Second, there are Hypercard "applications" that use
multiple stacks, and that share resources between stacks.  In this
case the user may never done so much as created a button or typed
"find" into the message window.  Again, such resources must be
installed into Hypercard or the Home stack, so an installer is
necessary.  And of course the installer must check for collisions with
existing resource names or ids.

>>I say go ahead and use embedded strings.  Hypercard is not really
>>script-manager friendly, and many stacks do lots of string munging
>>that is not fully language-independent.  When you get right down to
>>it, XCMDs are basically a hack. Lets not worry too hard about whether
>>we're following all the compatibility rules.

(I forgot the :-))

>The last sentence is too obviously screwy to bother refuting, but there
>is an interesting issue earlier on.  You can be internationalizable
>without being Script Manager friendly -- there are really two levels of
>international portability.  One is when you're compatible with other
>Indo-European languages that use one-byte-per-character alphabets and
>separate words using spaces; the other is where you're compatible with
>any language that can be crammed into the Script Manager.  The claimed
>HC incompatibility with the Script Manager may be real, but on the
>other hand, HC *is* pretty Europe-friendly.  Any developer who doesn't
>want to break this would be well advised to use separate strings.

I agree, although as one who works with languages "crammed into the
Script manager," I find partial internationalization unsatisfactory.
Rather like having an application 3/4 debugged :-).  But it may be the
best you can do, and if you anticipate users with native languages
different from your own, by all means use separate strings (and watch
out for number, date, time, and monetary formats, which might switch on
you).  On the other hand, if you don't plan on wide distribution and
want some string constants that only programmers will see--such as
returning the keyword "Error" at the start of an XFCN result string,
or named parameters to an XCMD--then embedded constants may be the
most expedient, if not the most professional, solution.

>Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim

Doug Felt
Courseware Authoring Tools Project
duggie@jessica.stanford.edu

duggie@Jessica.stanford.edu (Doug Felt) (04/22/89)

In article <2810@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes

>The problem is more generic: it is not just strings, but other resources
>as well (PICT, MENU, DLOG, ICN#, etc) that one might want to tie to an
>XCMD.  I'm not necessarily advocating all that stuff, nor would I be likely
>to use it all in a single XCMD or group thereof.  In the absence of an
>"owned resource" definition, I have to find some way to embed EVERYTHING in
>the XCMD resource itself.

Yes.  Or make up your own definition of owned resources for this
purpose, and write an installer that recognizes it.

(quote of my heretical statement omitted)

>... XCMDs provide a way to EXTEND a powerful user-
>interface engine.  The present mechanism is inadequate; it needs better
>engineering, it is not an excuse for user-interface anarchy.

Oh, a little anarchy helps grease the wheels a bit... :-) 

I would not call Hypercard a powerful user-interface engine.  Rather,
it is a bit of "interesting anarchy" that happens to be distributed to
hundreds of thousands of people for free by a large computer company.
Like the 128K Mac, its uses are limited.  Like the 128K Mac, it is
essentially an enormous beta test (Will users learn Hypertalk?  What
will they do with cards and buttons?  Let's find out!).  And, like the
128K Mac, we will be struggling to get out from under its quirks for
many years to come.  That said, it is undeniably a "seminal" product,
(we like to use that word in the educational community) and I hope
people take a look at the various ideas and run in different
directions with them.

I have long been an advocate of "applicationless environments" where
instead of applications there are just chunks of code that perform
different functions. The granularity would be smaller than an
application but larger than a routine (XCMD).  These chunks, plus
other resources, would be managed by a database in the operating
system.  With a number of object-oriented systems starting to
stabilize on user interface classes, it starts to look possible to
partition out the user interface from the code.  And perhaps when we
get rid of applications we can get rid of files (as user-visible
entities with fixed data formats) too.  Ditto for directories.  (Users
do need to organize their work, but hierarchical directories are not
the best way to do it).

In short, we need more anarchy, as long as it's interesting.  These
string (resource) problems have to be solved, for the moment, but
they're not interesting, and "anarchy" here is just randomness,
neither useful nor, in my opinion, terribly harmful.  I say develop a
nested resource format and a replacement for the resource manager.
Now that would be anarchy!

>=Ned Horvath=

Doug ("overthrow toolbox tyranny") Felt
Courseware Authoring Tools Project
duggie@jessica.stanford.edu

afoster@ogccse.ogc.edu (Allan Foster) (04/24/89)

In article <2810@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes:

> ...When you get right down to
> it, XCMDs are basically a hack. Lets not worry too hard about whether
> we're following all the compatibility rules.
>
>=Ned Horvath=

Sorry Ned, but here I have to disagree!

XCMDs in their current implementation are a Bit of a hack, but they
are still very useful and important to extending not only HyperCard
but an increasing number of other applications as well.  

I see this as a good thing since other developers are going to force
Apple to come up with a good way to implement XCMD bundles.  If Apple
doesn't then WE WILL!  Just cause HyperCard started this whole thing
does not mean that they OWN the whole Idea!

My suggestion to this problem is to have a new resource type (maybe
XBDL?) that is the description of a xcmd bundle.  This is similar
to the bnld resource in an appl, but can also contain arg descriptors
for reminders to developers.  They can be removed if space is tight,
but at least XCMD users would have an idea of what params to give it!

Anyway nice to hear from you again!

Regards

Allan Foster -- GURU


-- 
Allan Foster      UUCP  : tektronix!ogcvax!afoster
CSNet : afoster@cse.ogc.edu      GEnie  : A.FOSTER
AppleLink : UG0035                 MacNet : FOSTER    

ech@pegasus.ATT.COM (Edward C Horvath) (04/25/89)

In article <2810@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes:
 
> ...When you get right down to
> it, XCMDs are basically a hack. Lets not worry too hard about whether
> we're following all the compatibility rules.
>
>=Ned Horvath=
 
From article <2442@ogccse.ogc.edu>, by afoster@ogccse.ogc.edu (Allan Foster):
> Sorry Ned, but here I have to disagree!
> 
> XCMDs in their current implementation are a Bit of a hack, but they
> are still very useful and important to extending not only HyperCard
> but an increasing number of other applications as well.  
 
AAAAARRRRGGGHHHH!!!  I have been DEFAMED!!! and by a FRIEND (or so I
thought) to boot!

Allan, I quoted some poor slob (who has been flamed enough) -- I CONDEMNED
this position, I didn't endorse it!

I assume this was an accident.  Else, I hope Maggie gives birth to an IBM
PC lover!  So there!

Some of the above is :-)  Love ya, Allan...

=Ned=

earleh@eleazar.dartmouth.edu (Earle R. Horton) (04/25/89)

     I have a nifty way to solve this problem once and for all, but it
requires the cooperation of the host application developer.  This
won't help you at all if you want to write 'XCMD' resources for the
present version of HyperCard, but may help if you are writing a host
application for which you are designing the code resource interface.

Application writer:

     Arrange to have in your A5-relative global space an unused area
of storage, located at the top of the global area and just below
register A5.  You can do this with the MPW and Aztec linkers by having
an array of whatever size which is (a) declared in your last-mentioned
object file on the link line and (b) referenced but not modified in
your source code.  While linking your program, arrange to have a link
map produced, and verify that the unused area of storage is, indeed,
at the top of the global data area.  

     Included in the specifications for your code resource type the
size of the free area below A5.  Custom code resources produced for
use with your application will use the area below A5 as their own
private global area, and will reference it normally with negative
short offsets off of A5.  These may initialize their global data in
the "normal" manner, i.e. the same method used for application code,
when you call them.  Make it extremely clear that anyone who uses more
A5-relative data space than this will crash your application.  The
idea here is that the APPLICATION WRITER, when he designs the program
at the start, specifically allows for an area of memory which can be
used by custom code resources to implement A5-relative global data.
(Your application uses the area below this for its own globals.)

     The code resource globals are even available from within Dialog
FilterProcs!  (Yes, I have this working in a program, and I am using
global variables, A5-relative string constants, A5-relative floating
point contstants, and all kinds of stuff like that from within my
custom code resources.)


Earle R. Horton

Graduate Student.  Programmer.  God to my cats.

afoster@ogccse.ogc.edu (Allan Foster) (04/28/89)

In article <2823@pegasus.ATT.COM> ech@pegasus.ATT.COM (Edward C Horvath) writes:
>AAAAARRRRGGGHHHH!!!  I have been DEFAMED!!! and by a FRIEND (or so I
>thought) to boot!
>
>Allan, I quoted some poor slob (who has been flamed enough) -- I CONDEMNED
>this position, I didn't endorse it!
>
>I assume this was an accident.  Else, I hope Maggie gives birth to an IBM
>PC lover!  So there!
>
>Some of the above is :-)  Love ya, Allan...
>
>=Ned=
AAARRRGGGHHHH  No Ned P L E A S E Not a PC LOVER!!!!!!!!!!!!!!

Sorry I thought you were on the other side,  my mistake!!
Glad to see you sticking up for poor old XCMDs, and the 
HIG Guidelines....

Sorry again, please take back the CURSE about the PC thing!

( I am hoping the first words it says are in 68000 assembly!)

Regards

Allan Foster - GURU




-- 
Allan Foster      UUCP  : tektronix!ogcvax!afoster
CSNet : afoster@cse.ogc.edu      GEnie  : A.FOSTER
AppleLink : UG0035                 MacNet : FOSTER