winfave@dutrun.UUCP (Alexander Verbraeck) (08/01/89)
There's one thing about Turbo Pascal that I don't understand, and that is the how the New procedure knows the size of the block on the heap to be allocated. At this moment some of my students are working on a heap manager on top of the standard TP heap manager that allows 4 Gbyte of heap space using paging and virtual memory swapping pages to (Ram)disk, where it is *not* neccesary to change any existing code. You can still use the standard ^ types, New and Dispose. If there is any interest in this manager when it is finished, I can post it to the net (if-and-only-if we succeed of course). The problem is that we do not understand the way the New procedure works. When you call New(P) where P points to a certain type, the New procedure allocates the correct number of bytes on the heap. We think that the compiler inserts some extra parameters when calling New, for the following program works _NOT_ ok: program TestNew(input,output); const AS = 500; type TT = array[1..AS] of integer; PT = ^TT; var IP,JP : PT; i,j : integer; procedure New(var P); begin System.New(pointer(P)); end; begin writeln(MemAvail); New(IP); writeln(MemAvail); System.New(JP); writeln(MemAvail); for i:=1 to AS do IP^[i]:=i; for i:=1 to AS do JP^[i]:=0; for j:=1 to 10 do write(IP^[j]:5); writeln; write('Press Enter'); readln; end. Output of this program is for instance: ------------------------------------------------------------ 502314 502314 --> No memory allocated at all! 501314 --> 1000 bytes allocated 0 0 0 0 0 0 0 0 0 0 Press Enter ------------------------------------------------------------ Which means that no memory is allocated during the New call, the correct amount of memory is allocated during the System.New call, and IP and JP share Heap-memory. Does anyone know what parameters are passed extra to the New procedure? How can I use these parameters? Is it possible to make a customized version of the New procedure? How do I get it to pass the right parameters on to the System.New procedure? --------------------------------------------------------------------- Alexander Verbraeck e-mail: Delft University of Technology winfave@hdetud1.bitnet Department of Information Systems winfave@dutrun.uucp PO Box 356, 2600 AJ The Netherlands ---------------------------------------------------------------------
ags@mentor.cc.purdue.edu (Dave Seaman) (08/01/89)
In article <845@dutrun.UUCP> winfave@dutrun.UUCP (A.Verbraeck) writes: >There's one thing about Turbo Pascal that I don't understand, >and that is the how the New procedure knows the size of the >block on the heap to be allocated. If you really want to do this, you should be using Modula-2 instead of Pascal. It has been a while since I looked at this, but the way I remember it is as follows. Modula-2 specifies that a call NEW(P) is translated into the system procedure ALLOCATE(P,n), where n is the size of the object to be allocated, and is determined by the compiler. ALLOCATE is imported from the SYSTEM module. The Pascal standard does not provide any implementation details for NEW. Therefore there is no guarantee that what you are asking is even possible in any given implementation, short of writing assembly code. There certainly is no portable way of doing it. -- Dave Seaman ags@seaman.cc.purdue.edu
abcscnuk@csuna.csun.edu (Naoto Kimura) (08/02/89)
In article <3534@mentor.cc.purdue.edu> ags@mentor.cc.purdue.edu (Dave Seaman) writes: >In article <845@dutrun.UUCP> winfave@dutrun.UUCP (A.Verbraeck) writes: >>There's one thing about Turbo Pascal that I don't understand, >>and that is the how the New procedure knows the size of the >>block on the heap to be allocated. > ... (text deleted) ... > >Dave Seaman >ags@seaman.cc.purdue.edu As far as I can guess, it performs a GetMem with the proper size, which is the size of the type that the pointer to points to. That is, if the pointer variable passed to New is a pointer to a record, it allocates enough memory to store that record type. It knows the size because it knows the record type and the size (as given by the SizeOf function). I haven't tried to send a Pointer type (just pointer, not a pointer to anything in particular) into New to see how much it allocates. It's really annoying that I can't allocate a 64K block (I can only allocate 64K - 1 byte). //-n-\\ Naoto Kimura _____---=======---_____ (abcscnuk@csuna.csun.edu) ====____\ /.. ..\ /____==== // ---\__O__/--- \\ Enterprise... Surrender or we'll \_\ /_/ send back your *&^$% tribbles !!
dmurdoch@watstat.waterloo.edu (Duncan Murdoch) (08/02/89)
In article <2110@csuna.csun.edu> abcscnuk@csuna.csun.edu (Naoto Kimura) writes: >It's >really annoying that I can't allocate a 64K block (I can only allocate >64K - 1 byte). It's really 64K - 15 bytes, and the reason is that the heap manager wants to be able to allocate it at any address, and still have it addressable within a single segment. If it gets allocated at ssss:$000F, then an offset of 64K - 1 would wrap around to the beginning of the segment. In any case though, the heap manager is fully documented, so you could write your own Getmem that wouldn't have this limitation, if you really need to. You'll have to disable range checking to be able to access all of it, but that's not a big deal. Duncan Murdoch
filbo@gorn.santa-cruz.ca.us (Bela Lubkin) (08/02/89)
In article <845@dutrun.UUCP> mcvax!hp4nl!dutrun!winfave@uunet.uu.net (A.Verbraeck) writes: >The problem is that we do not understand the way the New >procedure works. When you call New(P) where P points to a certain >type, the New procedure allocates the correct number of bytes on >the heap. We think that the compiler inserts some extra parameters >when calling New, for the following program works _NOT_ ok: You are right. Many Turbo Pascal "standard procedures" are not procedures per se. The most obvious example is Write/WriteLn: would it be possible to write those procedures (with variable numbers of arguments, special syntax for field widths, etc.) in the language as it's documented? (This must be true in most Pascal compilers.) New and Dispose are among the library routines that are called through some trickery. When you write New(Foo), the compiler generates code similar to that which would be generated for GetMem(Foo,SizeOf(Foo^)). This is not handled by a preprocessor, nor is GetMem ever actually called explicitly, so you cannot simply write a procedure named GetMem. I don't know of any way to completely transparently replace New & Dispose. You could buy the source to the library and replace the System unit, but as a programmer using your heap code I would not find it "transparent" to have to move your unit into my library. ADDing a unit would be fine; replacing one of the vendor's, no. Hmmm. Ok, I have a kludge for you. You'll have to do some digging in the reference manual for this; my manuals are still waiting to be moved from my previous residence. Turbo's standard New/GetMem will call an exception routine if there's not enough heap to satisfy your request. You can install your routines as that exception routine, then grab ALL of Turbo's heap for yours, so all allocation attempts will generate an exception. The pointer you return must point to a memory block that actually starts a few bytes lower than the pointer points to. Store the size of the block in this extra area. This allows you to write your own Dispose procedure which doesn't require magic parameters. (I don't think there's an exception routine for Dispose -- how could it fail?) All in all, a better solution would be to write transparent replacements for GetMem/FreeMem and disallow New/Dispose. (This is easily accomplished; just declare New/Dispose procedures with no parameters. These will hide the System unit versions and prevent any attempts to call them). >program TestNew(input,output); >const > AS = 500; >type > TT = array[1..AS] of integer; > PT = ^TT; >var > IP,JP : PT; > i,j : integer; >procedure New(var P); >begin > System.New(pointer(P)); ^^^^^^^^^^ Type "pointer" acts like a "C" "void *" -- it points to a structure of size 0. New(pointer(P)) is equivalent to GetMem(P,SizeOf(P^)), or GetMem(P,0), and allocates no memory. >end; > >begin > writeln(MemAvail); > New(IP); > writeln(MemAvail); > System.New(JP); > writeln(MemAvail); > for i:=1 to AS do IP^[i]:=i; > for i:=1 to AS do JP^[i]:=0; > for j:=1 to 10 do write(IP^[j]:5); > writeln; > write('Press Enter'); > readln; >end. Bela Lubkin * * filbo@gorn.santa-cruz.ca.us CIS: 73047,1112 @ * * ...ucbvax!ucscc!gorn!filbo ^^^ REALLY slow [months] R Pentomino * Filbo @ Pyrzqxgl (408) 476-4633 & XBBS (408) 476-4945
tarvaine@tukki.jyu.fi (Tapani Tarvainen) (08/03/89)
In article <3.filbo@gorn.santa-cruz.ca.us> filbo@gorn.santa-cruz.ca.us (Bela Lubkin) writes: > (I don't think there's an exception routine for >Dispose -- how could it fail?) Yes it can, rare though it is: There is a fixed size reserved for the free space list, and if you free a block that isn't adjacent to another, you need room for another entry. If memory becomes sufficiently fragmented, it is possible to fill the list. This is described on p. 197-198 in TP 5.0 Reference Guide; it says there is room for 8191 noncontiguous freed blocks. BTW, it isn't quite as unlikely as the manual suggests: it happened to me once! -- Tapani Tarvainen (tarvaine@jyu.fi, tarvainen@finjyu.bitnet)