newrpl/tempob.c
2014-05-21 13:47:14 -04:00

127 lines
3.6 KiB
C

/*
* Copyright (c) 2014, Claudio Lapilli and the newRPL Team
* All rights reserved.
* This file is released under the 3-clause BSD license.
* See the file LICENSE.txt that shipped with this distribution.
*/
#include "newrpl.h"
#include "hal.h"
// ALLOCATES MEMORY FROM TEMPOB
// SIZE IS THE NUMBER OF WORDS REQUIRED, NOT COUNTING THE PROLOG!
// IT AUTOMATICALLY RESERVES ONE EXTRA WORD FOR THE PROLOG
WORDPTR rplAllocTempOb(WORD size)
{
// SIMPLY ADD A NEW BLOCK AT END OF CHAIN
if( TempObEnd+size+1+TEMPOBSLACK>TempObSize) {
// ENLARGE TEMPOB AS NEEDED
growTempOb((BINT)(TempObEnd-TempOb)+size+1+TEMPOBSLACK);
if(Exceptions) return 0;
}
rplAddTempBlock(TempObEnd);
WORDPTR ptr=TempObEnd;
TempObEnd+=size+1;
return ptr;
}
// TRUNCATES A RECENTLY ALLOCATED BLOCK AT THE END OF TEMPOB
// IT HAS TO BE THE LAST BLOCK ALLOCATED WITH ALLOCTEMPOB
void rplTruncateLastObject(WORDPTR newend)
{
TempObEnd=newend;
}
// BORROW THE PATCH FUNCTION FROM THE GARBAGE COLLECTOR
extern void Patch(WORDPTR *start,WORDPTR *end,WORDPTR startfrom,WORDPTR endfrom,BINT offset);
// GROW THE TEMPORARY OBJECT MEMORY
void growTempOb(WORD newtotalsize)
{
WORDPTR *newtempob;
WORD slack=newtotalsize-(WORD)(TempObEnd-TempOb);
BINT gc_done=0;
do {
newtotalsize=(newtotalsize+1023)&~1023;
newtempob=hal_growmem((WORDPTR *)TempOb,newtotalsize);
if(!newtempob) {
if(!gc_done) { rplGCollect(); ++gc_done; newtotalsize=(WORD)(TempObEnd-TempOb)+slack; }
else {
Exceptions|=EX_OUTOFMEM;
ExceptionPointer=IPtr;
return;
}
}
} while(!newtempob);
if(((WORDPTR *)TempOb)!=newtempob) {
// TEMPOB HAD TO BE MOVED IN MEMORY
// FIX ALL DSTK/RSTK/TEMPBLOCKS/DIRECTORIES/LAMS POINTERS
Patch(DStk,DSTop,TempOb,TempObSize,newtempob-(WORDPTR *)TempOb); // DATA STACK
Patch(RStk,RSTop,TempOb,TempObSize,newtempob-(WORDPTR *)TempOb); // RETURN STACK
Patch(LAMs,LAMTop,TempOb,TempObSize,newtempob-(WORDPTR *)TempOb); // LOCAL VARIABLES
Patch(Directories,DirsTop,TempOb,TempObSize,newtempob-(WORDPTR *)TempOb); // GLOBAL VARIABLES
Patch(GC_PTRUpdate,GC_PTRUpdate+MAX_GC_PTRUPDATE,TempOb,TempObSize+1,newtempob-(WORDPTR *)TempOb); // SYSTEM POINTERS, USE TempObSize+1 TO UPDATE POINTERS POINTING TO END OF TEMPOB TOO
Patch(TempBlocks,TempBlocksEnd,TempOb,TempObSize,newtempob-(WORDPTR *)TempOb); // ALL TEMPBLOCK POINTERS
}
TempOb=(WORDPTR) newtempob;
TempObSize=TempOb+newtotalsize;
}
void growTempBlocks(WORD newtotalsize)
{
WORDPTR *newtempblocks;
WORD slack=newtotalsize-(WORD)(TempBlocksEnd-TempBlocks);
BINT gc_done=0;
do {
newtotalsize=(newtotalsize+1023)&~1023;
newtempblocks=hal_growmem(TempBlocks,newtotalsize);
if(!newtempblocks) {
if(!gc_done) { rplGCollect(); ++gc_done; newtotalsize=(WORD)((TempBlocksEnd+slack)-TempBlocks); }
else {
Exceptions|=EX_OUTOFMEM;
ExceptionPointer=IPtr;
return;
}
}
} while(!newtempblocks);
TempBlocksEnd=TempBlocksEnd-TempBlocks+newtempblocks;
TempBlocks=newtempblocks;
TempBlocksSize=newtotalsize;
// NOTHING TO FIX
}
// TEMPBLOCKS ARE INCREASE AFTER FOR WRITE, DECREASE BEFORE FOR READ.
void rplAddTempBlock(WORDPTR block)
{
*TempBlocksEnd++=block;
if(TempBlocksEnd+TEMPBLOCKSLACK>=TempBlocks+TempBlocksSize)
growTempBlocks(TempBlocksEnd-TempBlocks+TEMPBLOCKSLACK+1024);
if(Exceptions) return;
}