newrpl/newrpl/tempob.c
claudiol 7cba1a3e9b Added more RPL internal info to exception handlers.
Improved memory handling during GC.
2016-01-30 10:20:18 -05:00

203 lines
5.4 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);
if(Exceptions) return 0;
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)
{
if(newend<=*(TempBlocksEnd-1)) {
// TRIED TO TRUNCATE BEYOND THE LAST OBJECT, CAN'T ALLOW THAT
// REMOVE LAST ALLOCATED BLOCK COMPLETELY
--TempBlocksEnd;
TempObEnd=*TempBlocksEnd;
return;
}
TempObEnd=newend;
}
// RESIZE THE LAST OBJECT BY APPENDING WORDS AT THE END OF TEMPOB
// DOES NOT CREATE A NEW OBJECT OR A NEW BLOCK
// APPEND additionalsize WORDS TO THE END OF TEMPOB
void rplResizeLastObject(WORD additionalsize)
{
if( TempObEnd+additionalsize+TEMPOBSLACK>TempObSize) {
// ENLARGE TEMPOB AS NEEDED
growTempOb((BINT)(TempObEnd-TempOb)+additionalsize+TEMPOBSLACK);
if(Exceptions) return;
}
TempObEnd+=additionalsize;
}
// BORROW THE PATCH FUNCTION FROM THE GARBAGE COLLECTOR
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=halGrowMemory(MEM_AREA_TEMPOB,(WORDPTR *)TempOb,newtotalsize);
if(!newtempob) {
if(!gc_done) {
rplGCollect(); ++gc_done; newtotalsize=(WORD)(TempObEnd-TempOb)+slack; }
else {
rplException(EX_OUTOFMEM);
return;
}
}
} while(!newtempob);
if(TempOb && (((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;
// FOR DEBUG ONLY
//halCheckRplMemory();
}
// SHRINK THE TEMPORARY OBJECT MEMORY
// SAME AS GROW BUT DOESN'T GARBAGE COLLECT AND RETRY
void shrinkTempOb(WORD newtotalsize)
{
WORDPTR *newtempob;
newtotalsize=(newtotalsize+1023)&~1023;
newtempob=halGrowMemory(MEM_AREA_TEMPOB,(WORDPTR *)TempOb,newtotalsize);
if(!newtempob) {
rplException(EX_OUTOFMEM);
return;
}
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=halGrowMemory(MEM_AREA_TEMPBLOCKS,TempBlocks,newtotalsize);
if(!newtempblocks) {
if(!gc_done) {
rplGCollect();
++gc_done;
newtotalsize=(WORD)((TempBlocksEnd+slack)-TempBlocks); }
else {
rplException(EX_OUTOFMEM);
return;
}
}
} while(!newtempblocks);
TempBlocksEnd=TempBlocksEnd-TempBlocks+newtempblocks;
TempBlocks=newtempblocks;
TempBlocksSize=newtotalsize;
if(TempBlocksEnd>=TempBlocks+TempBlocksSize) throw_dbgexception("Bad TempBlocksEnd!",1);
// NOTHING TO FIX
}
void shrinkTempBlocks(WORD newtotalsize)
{
WORDPTR *newtempblocks;
newtotalsize=(newtotalsize+1023)&~1023;
newtempblocks=halGrowMemory(MEM_AREA_TEMPBLOCKS,TempBlocks,newtotalsize);
if(!newtempblocks) {
rplException(EX_OUTOFMEM);
return;
}
TempBlocksEnd=TempBlocksEnd-TempBlocks+newtempblocks;
TempBlocks=newtempblocks;
TempBlocksSize=newtotalsize;
if(TempBlocksEnd>=TempBlocks+TempBlocksSize) throw_dbgexception("Bad TempBlocksEnd!",__EX_CONT | __EX_RPLREGS);
// 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;
}