//for 64bit systems. :)
//addressable memory is memory available to the vm itself for writing.
//once allocated, it cannot be freed for the lifetime of the VM.
-void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount)
+void *PRAddressableExtend(progfuncs_t *progfuncs, int ammount)
{
ammount = (ammount + 4)&~3; //round up to 4
- if (addressableused + ammount > addressablesize)
+ if (prinst->addressableused + ammount > prinst->addressablesize)
{
/*only do this if the caller states that it can cope with addressable-block relocations/resizes*/
if (externs->addressablerelocated)
#if 0//def _DEBUG
int oldtot = addressablesize;
#endif
- int newsize = (addressableused + ammount + 4096) & ~(4096-1);
- newblock = VirtualAlloc (NULL, addressablesize, MEM_RESERVE, PAGE_NOACCESS);
+ int newsize = (prinst->addressableused + ammount + 4096) & ~(4096-1);
+ newblock = VirtualAlloc (NULL, prinst->addressablesize, MEM_RESERVE, PAGE_NOACCESS);
if (newblock)
{
- VirtualAlloc (newblock, addressableused, MEM_COMMIT, PAGE_READWRITE);
- memcpy(newblock, addressablehunk, addressableused);
+ VirtualAlloc (newblock, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE);
+ memcpy(newblock, prinst->addressablehunk, prinst->addressableused);
#if 0//def _DEBUG
- VirtualAlloc (addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS);
+ VirtualAlloc (prinst->addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS);
#else
- VirtualFree (addressablehunk, 0, MEM_RELEASE);
+ VirtualFree (prinst->addressablehunk, 0, MEM_RELEASE);
#endif
- PRAddressableRelocate(progfuncs, addressablehunk, newblock, addressableused);
- addressablehunk = newblock;
- addressablesize = newsize;
+ PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused);
+ prinst->addressablehunk = newblock;
+ prinst->addressablesize = newsize;
}
#else
char *newblock;
- int newsize = (addressableused + ammount + 1024*1024) & ~(1024*1024-1);
- newblock = realloc(newblock, addressablesize);
+ int newsize = (prinst->addressableused + ammount + 1024*1024) & ~(1024*1024-1);
+ newblock = realloc(newblock, prinst->addressablesize);
if (newblock)
{
- PRAddressableRelocate(progfuncs, addressablehunk, newblock, addressableused);
- addressablehunk = newblock;
- addressablesize = newsize;
+ PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused);
+ prinst->addressablehunk = newblock;
+ prinst->addressablesize = newsize;
}
#endif
}
- if (addressableused + ammount > addressablesize)
+ if (prinst->addressableused + ammount > prinst->addressablesize)
Sys_Error("Not enough addressable memory for progs VM");
}
- addressableused += ammount;
+ prinst->addressableused += ammount;
#ifdef _WIN32
- if (!VirtualAlloc (addressablehunk, addressableused, MEM_COMMIT, PAGE_READWRITE))
+ if (!VirtualAlloc (prinst->addressablehunk, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE))
Sys_Error("VirtualAlloc failed. Blame windows.");
#endif
- return &addressablehunk[addressableused-ammount];
+ return &prinst->addressablehunk[prinst->addressableused-ammount];
+}
+
+
+#define MARKER 0xF1E3E3E7u
+typedef struct
+{
+ unsigned int next;
+ unsigned int prev;
+ unsigned int size;
+} qcmemfreeblock_t;
+typedef struct
+{
+ unsigned int marker;
+ unsigned int size;
+} qcmemusedblock_t;
+static void PF_fmem_unlink(progfuncs_t *pr, qcmemfreeblock_t *p)
+{
+ qcmemfreeblock_t *np;
+ if (p->prev)
+ {
+ np = (qcmemfreeblock_t*)(pr->stringtable + p->prev);
+ np->next = p->next;
+ }
+ else
+ pr->inst->mfreelist = p->next;
+ if (p->next)
+ {
+ np = (qcmemfreeblock_t*)(pr->stringtable + p->next);
+ np->prev = p->prev;
+ }
+}
+static void *PR_memalloc (progfuncs_t *progfuncs, unsigned int size)
+{
+ qcmemfreeblock_t *p, *np;
+ qcmemusedblock_t *ub = NULL;
+ unsigned int b,n;
+ /*round size up*/
+ size = (size+sizeof(qcmemusedblock_t) + 63) & ~63;
+
+ b = prinst->mfreelist;
+ while (b)
+ {
+ if (b < 0 || b >= prinst->addressableused)
+ {
+ printf("PF_memalloc: memory corruption\n");
+ PR_StackTrace(progfuncs);
+ return NULL;
+ }
+ p = (qcmemfreeblock_t*)(progfuncs->stringtable + b);
+ if (p->size >= size)
+ {
+ if (p->next && p->next < b + p->size ||
+ p->next >= prinst->addressableused ||
+ b + p->size >= prinst->addressableused ||
+ p->prev >= b)
+ {
+ printf("PF_memalloc: memory corruption\n");
+ PR_StackTrace(progfuncs);
+ return NULL;
+ }
+
+ ub = (qcmemusedblock_t*)p;
+ if (p->size > size + 63)
+ {
+ /*make a new header just after it, with basically the same properties, and shift the important fields over*/
+ n = b + size;
+ np = (qcmemfreeblock_t*)(progfuncs->stringtable + b + size);
+ np->prev = p->prev;
+ np->next = p->next;
+ np->size = p->size - size;
+ if (np->prev)
+ {
+ p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->prev);
+ p->next = n;
+ }
+ else
+ prinst->mfreelist = n;
+ if (p->next)
+ {
+ p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->next);
+ p->prev = n;
+ }
+ }
+ else
+ {
+ size = p->size; /*alloc the entire block*/
+ /*unlink this entry*/
+ PF_fmem_unlink(progfuncs, p);
+ }
+ break;
+ }
+ }
+
+ /*assign more space*/
+ if (!ub)
+ {
+ ub = PRAddressableExtend(progfuncs, size);
+ if (!ub)
+ {
+ printf("PF_memalloc: memory exausted\n");
+ PR_StackTrace(progfuncs);
+ return NULL;
+ }
+ }
+ memset(ub, 0, size);
+ ub->marker = MARKER;
+ ub->size = size;
+ return ub+1;
+}
+static void PR_memfree (progfuncs_t *progfuncs, void *memptr)
+{
+ qcmemusedblock_t *ub;
+ qcmemfreeblock_t *p, *np;
+ unsigned int l, ln;
+ unsigned int size;
+ unsigned int ptr = memptr?((char*)memptr - progfuncs->stringtable):0;
+
+ /*freeing NULL is ignored*/
+ if (!ptr)
+ return;
+ if (ptr < sizeof(qcmemusedblock_t) || ptr >= prinst->addressableused)
+ {
+ printf("PF_memfree: pointer invalid - out of range (%u >= %u)\n", ptr, prinst->addressableused);
+ PR_StackTrace(progfuncs);
+ return;
+ }
+
+ ub = (qcmemusedblock_t*)(progfuncs->stringtable + ptr);
+ ub--;
+ ptr = (char*)ub - progfuncs->stringtable;
+ if (ub->marker != MARKER || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst->addressableused)
+ {
+ printf("PF_memfree: memory corruption or double free\n");
+ PR_StackTrace(progfuncs);
+ return;
+ }
+ ub->marker = 0;
+ size = ub->size;
+
+ for (ln = prinst->mfreelist, l = 0; ;)
+ {
+ if (ln < 0 || ln >= prinst->addressableused)
+ {
+ printf("PF_memfree: memory corruption\n");
+ PR_StackTrace(progfuncs);
+ return;
+ }
+ if (!ln || ln >= ptr)
+ {
+ np = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
+ if (l && l+np->size>ptr)
+ {
+ printf("PF_memfree: double free\n");
+ PR_StackTrace(progfuncs);
+ return;
+ }
+
+ /*generate the free block, now we know its proper values*/
+ p = (qcmemfreeblock_t*)(progfuncs->stringtable + ptr);
+ p->prev = l;
+ p->next = ln;
+ p->size = size;
+
+ /*update the next's previous*/
+ if (p->next)
+ {
+ np = (qcmemfreeblock_t*)(progfuncs->stringtable + p->next);
+ np->prev = p->prev;
+
+ /*extend this block and kill the next if they are adjacent*/
+ if (p->next == ptr + size)
+ {
+ p->size += np->size;
+ PF_fmem_unlink(progfuncs, np);
+ }
+ }
+
+ /*update the link to get here*/
+ if (!l)
+ prinst->mfreelist = ptr;
+ else
+ {
+ np = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
+ np->next = ptr;
+
+ /*we're adjacent to the previous block, so merge them by killing the newly freed region*/
+ if (l + np->size == ptr)
+ {
+ np->size += size;
+ PF_fmem_unlink(progfuncs, p);
+ }
+ }
+ break;
+ }
+
+ l = ln;
+ p = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
+ ln = p->next;
+ }
}
void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount)
{
- addressableused = 0;
+ prinst->addressableused = 0;
if (totalammount < 0) //flush
{
- totalammount = addressablesize;
+ totalammount = prinst->addressablesize;
// return;
}
#ifdef _WIN32
- if (addressablehunk && addressablesize != totalammount)
+ if (prinst->addressablehunk && prinst->addressablesize != totalammount)
{
- VirtualFree(addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
- addressablehunk = NULL;
+ VirtualFree(prinst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
+ prinst->addressablehunk = NULL;
}
- if (!addressablehunk)
- addressablehunk = VirtualAlloc (addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS);
+ if (!prinst->addressablehunk)
+ prinst->addressablehunk = VirtualAlloc (prinst->addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS);
#else
- if (addressablehunk)
- free(addressablehunk);
- addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy.
-// memset(addressablehunk, 0xff, totalammount);
+ if (prinst->addressablehunk && prinst->addressablesize != totalammount)
+ {
+ free(prinst->addressablehunk);
+ prinst->addressablehunk = NULL;
+ }
+ if (!prinst->addressablehunk)
+ prinst->addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy.
+// memset(prinst->addressablehunk, 0xff, totalammount);
#endif
- if (!addressablehunk)
+ if (!prinst->addressablehunk)
Sys_Error("Out of memory\n");
- addressablesize = totalammount;
+ prinst->addressablesize = totalammount;
}
int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *));
sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize);
prinst->edicttable[0] = sv_edicts;
- ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableAlloc(progfuncs, max_fields_size);
+ ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableExtend(progfuncs, max_fields_size);
QC_ClearEdict(progfuncs, sv_edicts);
sv_num_edicts = 1;
if (!str)
return 0;
- if (str >= progfuncs->stringtable && str < progfuncs->stringtable + addressableused)
+ if (str >= progfuncs->stringtable && str < progfuncs->stringtable + prinst->addressableused)
return str - progfuncs->stringtable;
for (i = prinst->numallocedstrings-1; i >= 0; i--)
}
}
- if (str >= addressableused)
+ if ((unsigned int)str >= (unsigned int)prinst->addressableused)
{
printf("invalid string offset %x\n", str);
PR_StackTrace(progfuncs);
PR_QueryField,
QC_ClearEdict,
QC_FindPrefixedGlobals,
- PRAddressableAlloc,
- PR_AllocTempStringLen
+ PR_memalloc,
+ PR_AllocTempStringLen,
+ PR_memfree,
};
#undef printf
#undef extensionbuiltin
#undef field
#undef shares
+#undef maxedicts
#undef sv_num_edicts
f = inst->parms->memfree;
- for ( i=1 ; i<inst->maxedicts; i++)
+ for ( i=1 ; i<inst->inst->maxedicts; i++)
{
- e = (edictrun_t *)(inst->prinst->edicttable[i]);
- inst->prinst->edicttable[i] = NULL;
+ e = (edictrun_t *)(inst->inst->edicttable[i]);
+ inst->inst->edicttable[i] = NULL;
if (e)
{
// e->entnum = i;
PRHunkFree(inst, 0);
#ifdef _WIN32
- VirtualFree(inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
+ VirtualFree(inst->inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
#else
- free(inst->addressablehunk);
+ free(inst->inst->addressablehunk);
#endif
- if (inst->prinst->allocedstrings)
- f(inst->prinst->allocedstrings);
- inst->prinst->allocedstrings = NULL;
- if (inst->prinst->tempstrings)
- f(inst->prinst->tempstrings);
- inst->prinst->tempstrings = NULL;
+ if (inst->inst->allocedstrings)
+ f(inst->inst->allocedstrings);
+ inst->inst->allocedstrings = NULL;
+ if (inst->inst->tempstrings)
+ f(inst->inst->tempstrings);
+ inst->inst->tempstrings = NULL;
/*
inst->prinst->extensionbuiltin = eb;
}
*/
- if (inst->prinst->field)
- f(inst->prinst->field);
- if (inst->prinst->shares)
- f(inst->prinst->shares); //free memory
- f(inst->prinst);
+ if (inst->inst->field)
+ f(inst->inst->field);
+ if (inst->inst->shares)
+ f(inst->inst->shares); //free memory
+ f(inst->inst);
f(inst);
}
}
#undef memalloc
#undef pr_trace
+#undef pr_progstate
+#undef pr_argc
funcs = ext->memalloc(sizeof(progfuncs_t));
memcpy(funcs, &deffuncs, sizeof(progfuncs_t));
- funcs->prinst = ext->memalloc(sizeof(prinst_t));
- memset(funcs->prinst,0, sizeof(prinst_t));
+ funcs->inst = ext->memalloc(sizeof(prinst_t));
+ memset(funcs->inst,0, sizeof(prinst_t));
- funcs->pr_trace = &funcs->prinst->pr_trace;
- funcs->progstate = &funcs->pr_progstate;
- funcs->callargc = &funcs->pr_argc;
+ funcs->pr_trace = &funcs->inst->pr_trace;
+ funcs->progstate = &funcs->inst->progstate;
+ funcs->callargc = &funcs->inst->pr_argc;
funcs->parms = ext;