[comp.sys.mac.programmer] StripAddress

gstein@oracle.uucp (Gregory Stein) (02/02/90)

[ I posted this once before and received no response, so I'm trying
  again... ]

Geez, it seems like StripAddress needs to be called *everywhere* if
you want to be 32-bit clean.  If you maintain any kind of information
within a handle, it appears that you are required to call StripAddress
to access that information.  Now, sure, I can dereference, strip it,
and store it so that I don't have to call StripAddress again (say, in
a sequence of stores), but as soon as I call a routine that moves
memory, I'll have to do it again.

I've been programming the Mac for almost six years now, but this whole
issue has me kind of stymied.  Am I missing something here?  For a
concrete example, let's define a structure like this:

    struct foo {
	int a, b, c;
    } **bar;
    bar = (struct foo **) NewHandle(sizeof(struct foo));

Now, when I say "(*bar)->a" is this 32-bit clean?  For this example
and the current system software it is because the flag bits in the
handle represented by bar are zero, so there is no problem (the object
is not locked, purgable, or a resource).  What happens if I do
something like:

	HLock((Handle)bar);
	(*bar)->a = f();		/* f() and g() move memory */
	(*bar)->b = g();
	HUnlock((Handle)bar);

Now, is this fragment still 32-bit clean?  I would assume it isn't
because when the dereference (*bar) occurs, I pick up the flag bit in
the master pointer.  The solution would be to add a StripAddress, but
what would happen if I did something like:

	(*bar)->a = 50;
	f();
	(*bar)->b = 60;
	g();
	(*bar)->c = 70;

Do I have to add a strip address everywhere?  Well, maybe.  I might
have this code fragment in a routine that takes bar as a parameter.
The calling function may pass a normal handle or a resource handle.

Well, what should I do?  Calling StripAddress everywhere seems like a
job for Mr. Anal Retentive Programmer.  Should I ignore the issue when
dealing with handles?  i.e. if I get a handle with flag bits in the
master pointer, then I'm in 24-bit mode and I don't care, but if it
has no flag bits then I'm in 32-bit mode and I still don't care?  This
seems to be appropriate, but it also seems like the Mac can run in
32-bit mode but still use the current Memory Manager.  Or is 32-bit
mode only supposed to be turned on by, say, a NuBus driver who uses
lots of StripAddress calls and then turns 32-bit mode off?

Thanx for any input.
--
Greg Stein	-- This posting bears no relation to my employer
Arpa: gstein%oracle.uucp@apple.com
UUCP: ..!{uunet,apple}!oracle!gstein

keith@Apple.COM (Keith Rollin) (02/02/90)

In article <1990Feb2.010425.28126@oracle.com> gstein@oracle.uucp (Gregory Stein) writes:
>
>Geez, it seems like StripAddress needs to be called *everywhere* if
>you want to be 32-bit clean.  If you maintain any kind of information
>within a handle, it appears that you are required to call StripAddress
>to access that information.  Now, sure, I can dereference, strip it,
>and store it so that I don't have to call StripAddress again (say, in
>a sequence of stores), but as soon as I call a routine that moves
>memory, I'll have to do it again.
>
>I've been programming the Mac for almost six years now, but this whole
>issue has me kind of stymied.  Am I missing something here?  For a
>concrete example, let's define a structure like this:
>
>    struct foo {
>	int a, b, c;
>    } **bar;
>    bar = (struct foo **) NewHandle(sizeof(struct foo));
>
>Now, when I say "(*bar)->a" is this 32-bit clean?  For this example
>and the current system software it is because the flag bits in the
>handle represented by bar are zero, so there is no problem (the object
>is not locked, purgable, or a resource).  What happens if I do
>something like:
>
>	HLock((Handle)bar);
>	(*bar)->a = f();		/* f() and g() move memory */
>	(*bar)->b = g();
>	HUnlock((Handle)bar);
>
>Now, is this fragment still 32-bit clean?  I would assume it isn't
>because when the dereference (*bar) occurs, I pick up the flag bit in
>the master pointer.  

Of course it's 32-bit clean. In 24-bit mode, the hardware effectively ignores
the high bits, so we used them for tag bits. In 32-bit mode, we naturally can't 
use the high byte for flags, or you would still be limited to a 24-bit address 
space. So when you are in 32-bit mode, the Memory Manager puts the bits 
elsewhere, freeing up the upper byte for address lines (there's actually a 
parallel 512 megabyte space in machines with the 32-bit Memory Manager, so 
that we can store the tag bits there  :-)

You only have to use StripAddress if you need to do master pointer comparisons
or pointer arithmetic (e.g. subtract two pointers to find the size of data
between them).

-- 
------------------------------------------------------------------------------
Keith Rollin  ---  Apple Computer, Inc.  ---  Developer Technical Support
INTERNET: keith@apple.com
    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith
"Argue for your Apple, and sure enough, it's yours" - Keith Rollin, Contusions

am524@umd5.umd.edu (Matthew T. Russotto) (02/02/90)

In article <1990Feb2.010425.28126@oracle.com> gstein@oracle.uucp (Gregory Stein) writes:
+>[ I posted this once before and received no response, so I'm trying
+>  again... ]
+>
+>
+>    struct foo {
+>	int a, b, c;
+>    } **bar;
+>    bar = (struct foo **) NewHandle(sizeof(struct foo));
+>
+>Now, when I say "(*bar)->a" is this 32-bit clean?  For this example
+>and the current system software it is because the flag bits in the
+>handle represented by bar are zero, so there is no problem (the object
+>is not locked, purgable, or a resource).
Yes.  The problem with the flag bits being in the upper 8 bits of the master
pointer is NOT YOUR PROBLEM.  It is the MEMORY MANAGER itself which is NOT
32-bit clean (naturally, on 32-bit clean systems, the memory manager IS
32-bit clean, and the flags are stored elsewhere)

+>  What happens if I do something like:
+>
+>	HLock((Handle)bar);
+>	(*bar)->a = f();		/* f() and g() move memory */
+>	(*bar)->b = g();
+>	HUnlock((Handle)bar);
+>
+>Now, is this fragment still 32-bit clean? 
Yes.

+>Well, what should I do?  Calling StripAddress everywhere seems like a
+>job for Mr. Anal Retentive Programmer.  Should I ignore the issue when
+>dealing with handles?  i.e. if I get a handle with flag bits in the
+>master pointer, then I'm in 24-bit mode and I don't care, but if it
+>has no flag bits then I'm in 32-bit mode and I still don't care?  This
+>seems to be appropriate, but it also seems like the Mac can run in
+>32-bit mode but still use the current Memory Manager.  Or is 32-bit
+>mode only supposed to be turned on by, say, a NuBus driver who uses
+>lots of StripAddress calls and then turns 32-bit mode off?

You just summarized the right answer-- I can think of only two reasons
to call StripAddress-- one is when comparing master pointers, so you
don't get the flags (why you would want to compare master pointers is
a different question).  The other is when you have 32-bit mode on with
an UNCLEAN memory manager.  Then, it will strip Memory manager generated
pointers so your routine can still get at them (instead of wrapping into
bus-errorville).  Most programs will run with 24-bit mode always on.
On a 32-bit clean system, StripAddress returns its argument unchanged.

siegel@endor.harvard.edu (Rich Siegel) (02/02/90)

In article <1990Feb2.010425.28126@oracle.com> gstein@oracle.uucp (Gregory Stein) writes:
>[ I posted this once before and received no response, so I'm trying
>  again... ]
>
>Geez, it seems like StripAddress needs to be called *everywhere* if
>you want to be 32-bit clean.  If you maintain any kind of information
>within a handle, it appears that you are required to call StripAddress
>to access that information.  Now, sure, I can dereference, strip it,
>and store it so that I don't have to call StripAddress again (say, in
>a sequence of stores), but as soon as I call a routine that moves
>memory, I'll have to do it again.

	Not quite. You should call StripAddress if you want to be sure
that the address you get by dereferencing a handle is clear of any
extra information such as flag bits. This is useful if you're planning to
do any kind of address arithmetic. However, in the normal case, you
can double-indirect a locked (or purgeable, or resource) handle and 
still get the right thing, because the system only uses the low-order
24 bits of whatever addresses you use.

	When the system runs in 32-bit mode, the flag bits will be kept
in some place other than the high byte of the handle, since the system
will use all 32 bits of the address. This means that you can still
single-and double-indirect handles safely, but you should NOT use
$00FFFFFF as a mask to get rid of the flag bits, since you'll smash
the upper 8 bits of a 32-bit address and end up with a pointer to hell. :-)


R.
~~~~~~~~~~~~~~~
 Rich Siegel
 Staff Software Developer
 Symantec Corporation, Language Products Group
 Internet: siegel@endor.harvard.edu
 UUCP: ..harvard!endor!siegel

"When someone who makes four hundred and fifty dollars an hour wants to
tell you something for free, it's a good idea to listen."

~~~~~~~~~~~~~~~

paul@taniwha.UUCP (Paul Campbell) (02/04/90)

In article <1461@husc6.harvard.edu> siegel@endor.UUCP (Rich Siegel) writes:
>In article <1990Feb2.010425.28126@oracle.com> gstein@oracle.uucp (Gregory Stein) writes:
>>
>>Geez, it seems like StripAddress needs to be called *everywhere* if
>>you want to be 32-bit clean.  If you maintain any kind of information
>
>	Not quite. You should call StripAddress if you want to be sure
>that the address you get by dereferencing a handle is clear of any
>extra information such as flag bits. This is useful if you're planning to
>do any kind of address arithmetic. However, in the normal case, you
>can double-indirect a locked (or purgeable, or resource) handle and 
>still get the right thing, because the system only uses the low-order
>24 bits of whatever addresses you use.

It is also a problem if you are going to do a SwapMMUMode(1) call to get to
32-bit addressing on a 24-bit system in order to access a board with
more than 1Mb of slot space and then want to work with any indirected
handle, including the address of HLock()ed code - you have to load the
address of code, Stripaddress it and jump to it ie:


	lea	@1, a0
	move.l	a0, d0
	_StripAddress
	move.l	d0, a0
	jmp	(a0)
@1:	
	move.l	#1, d0
	_SwapMMUMode



	Paul

-- 
Paul Campbell    UUCP: ..!mtxinu!taniwha!paul     AppleLink: CAMPBELL.P
"Skifield": N, device to collect and refine assholes

dwb@archer.apple.com (David W. Berry) (02/06/90)

In article <1990Feb2.010425.28126@oracle.com> gstein@oracle.uucp (Gregory Stein) writes:
>[ I posted this once before and received no response, so I'm trying
>  again... ]
>
>    struct foo {
>	int a, b, c;
>    } **bar;
>    bar = (struct foo **) NewHandle(sizeof(struct foo));
>
>Now, when I say "(*bar)->a" is this 32-bit clean?  For this example
	Yes.  If the flag bits are in the upper byte, the memory
mapping hardware will be set to ignore the upper byte.  If full
32 bit addresses are being used, the flags will be kept somewhere
other than the upper byte.  The primary things to remember to
be 32 bit clean are:

1.  Don't use bset/bclr to change or access flag bytes.  Use HLock,
HGetState, etc.

2.  Don't fake handles.  A handle and an &Pointer aren't the same thing.
If you want to include your custom ?DEF in line in your program the
following routine is real handy:

	ProcHandle ProcToHandle(ProcPtr proc)
	{
		struct ProcJmp {
			short		jmp;
			ProcPtr		addr;
		} **hand;

		hand = (struct ProcJmp **) NewHandle(sizeof(**hand));
		(**hand).jmp = 0x4ef9;
		(**hand).addr = StripAddress(proc);	/* excessive paranoia */

		return (ProcHandle) hand;
	}

3.  Don't try to walk the zone.  The zone format is subject to change.
If it changes you'll likely blow up.

4.  Use GetWVariant and GetCVariant instead of using the upper byte
of the definition routine.  If you have to set the variant be real
careful, remember to check for an auxilliary record and change the
variant there if it exists.  If not set it in the upper byte.

CXT105@psuvm.psu.edu (Christopher Tate) (11/19/90)

Do I need to call StripAddress() in the following situation?  Here's the
relevant code:

Handle        myHand;
unsigned char *myPtr;

myHand = NewHandle(AMOUNT);
HLock(myHand);
myPtr = StripAddress(*myHand);    /* <-- do I need to do this? */
/* Now, put stuff into the block, using and incrementing myPtr */

Do I need to call StripAddress(*myHand) to make sure I get a valid
pointer into the block?  I *think* I do, because the master pointer
might have strange stuff in it, but I'm not sure, and the tech note
isn't too clear on this....

-------
Christopher Tate                      |                      etaT rehpotsirhC
Bitnet: cxt105@psuvm                  |                  mvusp@501txc :tentiB
Uucp: ...!psuvax1!psuvm.bitnet!cxt105 | 501txc!tentib.mvusp!1xavusp!... :pcuU
Internet: cxt105@psuvm.psu.edu        |        ude.usp.mvusp@501txc :tenretnI

wilkins@jarthur.Claremont.EDU (Mark Wilkins) (11/20/90)

In article <90323.102417CXT105@psuvm.psu.edu> CXT105@psuvm.psu.edu (Christopher Tate) writes:
>Do I need to call StripAddress() in the following situation?  Here's the
>relevant code:
>
>Handle        myHand;
>unsigned char *myPtr;
>
>myHand = NewHandle(AMOUNT);
>HLock(myHand);
>myPtr = StripAddress(*myHand);    /* <-- do I need to do this? */
>/* Now, put stuff into the block, using and incrementing myPtr */
>
>Do I need to call StripAddress(*myHand) to make sure I get a valid
>pointer into the block?

  NO, you do not, and in a tight loop you shouldn't.  Here's my logic:

  myHand points to a master pointer like this when running in 24-bit mode:

     xxxx xxxx 0000 0000   0000 0000 0000 0000

   where the x's are mem. manager flags and the 0's are address data.

  In 32-bit mode the master pointer looks like this:

     0000 0000 0000 0000   0000 0000 0000 0000

  If you make a copy of the master pointer and increment it by two, you get
the following:

     xxxx xxxx 0000 0000   0000 0000 0000 0010   (24-bit)
     0000 0000 0000 0000   0000 0000 0000 0010   (32-bit)

  However, the 24-bit memory manager ignores the top 8 bits, whereas the
32-bit memory manager does not.  So you get the right address when you
access your incremented pointer.

  The case where StripAddress is needed is where you could be running in
24-bit mode and you call SwapMMUMode to set the addressing to 32-bit for a
short time, as is necessary when accessing PixMap data directly.  In that
case, you need to make sure that the address is stripped before switching,
because if it is not, the system will bus error when it tries to evaluate
the flags as address bits.

-- Mark Wilkins
-- 
*******     "Freedom is a road seldom traveled by the multitude!"    **********
*-----------------------------------------------------------------------------*
*  Mark R. Wilkins   wilkins@jarthur.claremont.edu   {uunet}!jarthur!wilkins  *
******  MARK.WILKINS on AppleLink  ******   MWilkins on America Online   ******

stevec@Apple.COM (Steve Christensen) (11/20/90)

CXT105@psuvm.psu.edu (Christopher Tate) writes:
>Do I need to call StripAddress() in the following situation?  Here's the
>relevant code:
>
>Handle        myHand;
>unsigned char *myPtr;
>
>myHand = NewHandle(AMOUNT);
>HLock(myHand);
>myPtr = StripAddress(*myHand);    /* <-- do I need to do this? */
>/* Now, put stuff into the block, using and incrementing myPtr */
>
>Do I need to call StripAddress(*myHand) to make sure I get a valid
>pointer into the block?  I *think* I do, because the master pointer
>might have strange stuff in it, but I'm not sure, and the tech note
>isn't too clear on this....

No, the pointer is valid without calling StripAddress().  In 24-bit addressing
mode (non-A/UX, non-VM), the upper 8 bits of a pointer can contain some
bits used by the Memory Manager, but they're ignored for address purposes.
Generally you only need to call StripAddress if you need to compare two
addresses, since then the full 32 bits is used...

steve

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  whoami?     Steve Christensen
  snail:      Apple Computer, 20525 Mariani Ave, MS-81CS, Cupertino, CA 95035
  internet:   stevec@apple.com
  AppleLink:  stevec
  CompuServe: 76174,1712

russotto@eng.umd.edu (Matthew T. Russotto) (11/20/90)

In article <90323.102417CXT105@psuvm.psu.edu> CXT105@psuvm.psu.edu (Christopher Tate) writes:
>Do I need to call StripAddress() in the following situation?  Here's the
>relevant code:
>
>Handle        myHand;
>unsigned char *myPtr;
>
>myHand = NewHandle(AMOUNT);
>HLock(myHand);
>myPtr = StripAddress(*myHand);    /* <-- do I need to do this? */
>/* Now, put stuff into the block, using and incrementing myPtr */
>
>Do I need to call StripAddress(*myHand) to make sure I get a valid
>pointer into the block?  I *think* I do, because the master pointer
>might have strange stuff in it, but I'm not sure, and the tech note
>isn't too clear on this....

No.  Not in this case.  What will happen here is
IF 32-bit memory manager is running THEN
  no garbage in master ptr
ELSE (24 bit memory manager)
  garbage is ignored by MMU.

You would need it if you put the MMU in 32 bit mode when under a 24-bit
memory manager, i.e.

Handle        myHand;
unsigned char *myPtr;
extern Ptr hugebitmap /* 32-bit pointer into NuBus address space */

myHand = NewHandle(AMOUNT);
HLock(myHand);
myPtr = StripAddress(*myHand); 
oldmmumode = SwapMMUMode(32bitconstantwhateverthatis);
BlockMove(hugebitmap, myHand, amount);
SwapMMUMode(oldmmumode);
--
Matthew T. Russotto	russotto@eng.umd.edu	russotto@wam.umd.edu
     .sig under construction, like the rest of this campus.

chewy@apple.com (Paul Snively) (11/20/90)

In article <46697@apple.Apple.COM> stevec@Apple.COM (Steve Christensen) 
writes:
[Lead-in deleted for brevity's sake]
> Generally you only need to call StripAddress if you need to compare two
> addresses, since then the full 32 bits is used...

This is almost correct.  (It's obviously time to clarify my clarifications 
in the Tech Note.) ;-)

If you are comparing two pointers that lie within the same block, you're 
guaranteed cool regardless, because whether you're doing signed or 
unsigned math, everything works because the high byte is consistent.

The potential problems arise when you are comparing between pointers 
into _different_ blocks, particularly if:

1) the comparison is signed
2) one of the blocks is locked and
3) the other isn't

(Note that I'm assuming 24-bit mode here).

So the code in the original post is just fine.

Seriously, I _do_ plan to revise the Tech Note yet again, and perhaps 
rewrite it wholesale in English that's closer to what I just wrote.

Sorry 'bout the confusion,

__________________________________________________________________________
                                Paul Snively
                      Macintosh Developer Technical Support
                             Apple Computer, Inc.

chewy@apple.com

Just because I work for Apple Computer, Inc. doesn't mean that I believe 
what they believe, or vice-versa.
__________________________________________________________________________