mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
o all progs strings are now stored in progs memory
o temporary strings automaticly get freed when the function they're created in (results of str + str and most strings returned from builtins). a way to keep temp strings will be provided later o fix up qwaq to test the temp strings
This commit is contained in:
parent
40b8974c33
commit
bd561fafc3
6 changed files with 169 additions and 33 deletions
|
@ -156,7 +156,7 @@ qboolean PR_EdictValid (progs_t *pr, int e);
|
|||
#define R_FUNCTION(p) R_var (p, func)
|
||||
#define R_POINTER(p) R_var (p, pointer)
|
||||
|
||||
#define RETURN_STRING(p, s) (R_STRING (p) = PR_SetString((p), s))
|
||||
#define RETURN_STRING(p, s) (R_STRING (p) = PR_SetTempString((p), s))
|
||||
#define RETURN_EDICT(p, e) (R_STRING (p) = EDICT_TO_PROG(p, e))
|
||||
#define RETURN_POINTER(pr,p) (R_POINTER (pr) = POINTER_TO_PROG (pr, p))
|
||||
#define RETURN_VECTOR(p, v) (VectorCopy (v, R_VECTOR (p)))
|
||||
|
@ -221,7 +221,12 @@ int PR_InitRuntime (progs_t *pr);
|
|||
|
||||
qboolean PR_StringValid (progs_t *pr, int num);
|
||||
const char *PR_GetString(progs_t *pr, int num);
|
||||
struct dstring_s *PR_GetDString(progs_t *pr, int num);
|
||||
int PR_SetString(progs_t *pr, const char *s);
|
||||
int PR_SetTempString(progs_t *pr, const char *s);
|
||||
int PR_NewString (progs_t *pr);
|
||||
void PR_FreeString (progs_t *pr, int str);
|
||||
void PR_FreeTempStrings (progs_t *pr);
|
||||
void PR_GarbageCollect (progs_t *pr);
|
||||
|
||||
//
|
||||
|
@ -282,14 +287,9 @@ void PR_Cmds_Init (progs_t *pr);
|
|||
typedef struct {
|
||||
int s;
|
||||
dfunction_t *f;
|
||||
struct strref_s *tstr;
|
||||
} prstack_t;
|
||||
|
||||
typedef struct strref_s {
|
||||
struct strref_s *next;
|
||||
char *string;
|
||||
int count;
|
||||
} strref_t;
|
||||
|
||||
struct progs_s {
|
||||
const char *progs_name;
|
||||
dprograms_t *progs;
|
||||
|
@ -308,12 +308,14 @@ struct progs_s {
|
|||
pr_load_func_t **load_funcs;
|
||||
|
||||
// garbage collected strings
|
||||
strref_t *static_strings;
|
||||
strref_t **dynamic_strings;
|
||||
strref_t *free_string_refs;
|
||||
struct dstring_mem_s *ds_mem;
|
||||
struct strref_s *static_strings;
|
||||
struct strref_s **dynamic_strings;
|
||||
struct strref_s *free_string_refs;
|
||||
unsigned dyn_str_size;
|
||||
struct hashtab_s *strref_hash;
|
||||
int num_strings;
|
||||
struct strref_s *pr_xtstr;
|
||||
|
||||
dfunction_t *pr_functions;
|
||||
char *pr_strings;
|
||||
|
|
|
@ -137,6 +137,7 @@ PR_EnterFunction (progs_t * pr, dfunction_t *f)
|
|||
|
||||
pr->pr_xfunction = f;
|
||||
pr->pr_xstatement = f->first_statement - 1; // offset the st++
|
||||
pr->pr_xtstr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -158,10 +159,14 @@ PR_LeaveFunction (progs_t * pr)
|
|||
&pr->localstack[pr->localstack_used],
|
||||
sizeof (pr_type_t) * c);
|
||||
|
||||
if (pr->pr_xtstr)
|
||||
PR_FreeTempStrings (pr);
|
||||
|
||||
// up stack
|
||||
pr->pr_depth--;
|
||||
pr->pr_xfunction = pr->pr_stack[pr->pr_depth].f;
|
||||
pr->pr_xstatement = pr->pr_stack[pr->pr_depth].s;
|
||||
pr->pr_xtstr = pr->pr_stack[pr->pr_depth].tstr;
|
||||
}
|
||||
|
||||
#define OPA (*op_a)
|
||||
|
@ -280,7 +285,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
|
|||
char *c = Hunk_TempAlloc (size);
|
||||
strcpy (c, a);
|
||||
strcpy (c + lena, b);
|
||||
OPC.string_var = PR_SetString (pr, c);
|
||||
OPC.string_var = PR_SetTempString (pr, c);
|
||||
}
|
||||
break;
|
||||
case OP_SUB_F:
|
||||
|
|
|
@ -99,16 +99,14 @@ free_progs_mem (progs_t *pr, void *mem)
|
|||
void
|
||||
PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned i;
|
||||
int mem_size;
|
||||
dprograms_t progs;
|
||||
|
||||
pr->progs = 0;
|
||||
if (Qread (file, &progs, sizeof (progs)) != sizeof (progs))
|
||||
PR_Error (pr, "error reading header");
|
||||
|
||||
pr->progs_size = size;
|
||||
Sys_DPrintf ("Programs occupy %iK.\n", size / 1024);
|
||||
|
||||
// store prog crc
|
||||
pr->crc = CRC_Block ((byte*)&progs, sizeof (progs));
|
||||
|
||||
|
@ -137,6 +135,7 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone)
|
|||
|
||||
// size of progs themselves
|
||||
pr->progs_size = size;
|
||||
Sys_DPrintf ("Programs occupy %iK.\n", size / 1024);
|
||||
// round off to next highest whole word address (esp for Alpha)
|
||||
// this ensures that pointers in the engine data area are always
|
||||
// properly aligned
|
||||
|
@ -174,10 +173,11 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone)
|
|||
PR_Resources_Clear (pr);
|
||||
if (pr->progs)
|
||||
pr->free_progs_mem (pr, pr->progs);
|
||||
pr->progs = pr->allocate_progs_mem (pr, pr->progs_size + pr->zone_size
|
||||
+ pr->pr_edictareasize);
|
||||
mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize;
|
||||
pr->progs = pr->allocate_progs_mem (pr, mem_size + 1);
|
||||
if (!pr->progs)
|
||||
return;
|
||||
((byte *) pr->progs)[mem_size] = 0;
|
||||
|
||||
memcpy (pr->progs, &progs, sizeof (progs));
|
||||
Qread (file, pr->progs + 1, size - sizeof (progs));
|
||||
|
@ -194,7 +194,7 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone)
|
|||
pr->pr_functions =
|
||||
(dfunction_t *) ((byte *) pr->progs + pr->progs->ofs_functions);
|
||||
pr->pr_strings = (char *) pr->progs + pr->progs->ofs_strings;
|
||||
pr->pr_stringsize = pr->progs->numstrings;
|
||||
pr->pr_stringsize = (char *) pr->zone + pr->zone_size - (char *) pr->progs;
|
||||
pr->pr_globaldefs =
|
||||
(ddef_t *) ((byte *) pr->progs + pr->progs->ofs_globaldefs);
|
||||
pr->pr_fielddefs =
|
||||
|
|
|
@ -41,9 +41,37 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/progs.h"
|
||||
|
||||
typedef struct strref_s {
|
||||
struct strref_s *next;
|
||||
char *string;
|
||||
dstring_t *dstring;
|
||||
int count;
|
||||
} strref_t;
|
||||
|
||||
static void *
|
||||
pr_strings_alloc (void *_pr, size_t size)
|
||||
{
|
||||
progs_t *pr = (progs_t *) _pr;
|
||||
return PR_Zone_Malloc (pr, size);
|
||||
}
|
||||
|
||||
static void
|
||||
pr_strings_free (void *_pr, void *ptr)
|
||||
{
|
||||
progs_t *pr = (progs_t *) _pr;
|
||||
PR_Zone_Free (pr, ptr);
|
||||
}
|
||||
|
||||
static void *
|
||||
pr_strings_realloc (void *_pr, void *ptr, size_t size)
|
||||
{
|
||||
progs_t *pr = (progs_t *) _pr;
|
||||
return PR_Zone_Realloc (pr, ptr, size);
|
||||
}
|
||||
|
||||
static strref_t *
|
||||
new_string_ref (progs_t *pr)
|
||||
|
@ -74,6 +102,7 @@ static void
|
|||
free_string_ref (progs_t *pr, strref_t *sr)
|
||||
{
|
||||
sr->string = 0;
|
||||
sr->dstring = 0;
|
||||
sr->next = pr->free_string_refs;
|
||||
pr->free_string_refs = sr;
|
||||
}
|
||||
|
@ -110,7 +139,7 @@ strref_free (void *_sr, void *_pr)
|
|||
|
||||
// free the string and ref only if it's not a static string
|
||||
if (sr < pr->static_strings || sr >= pr->static_strings + pr->num_strings) {
|
||||
free (sr->string);
|
||||
PR_Zone_Free (pr, sr->string);
|
||||
free_string_ref (pr, sr);
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +155,14 @@ PR_LoadStrings (progs_t *pr)
|
|||
count++;
|
||||
str += strlen (str) + 1;
|
||||
}
|
||||
|
||||
if (!pr->ds_mem) {
|
||||
pr->ds_mem = malloc (sizeof (dstring_mem_t));
|
||||
pr->ds_mem->alloc = pr_strings_alloc;
|
||||
pr->ds_mem->free = pr_strings_free;
|
||||
pr->ds_mem->realloc = pr_strings_realloc;
|
||||
pr->ds_mem->data = pr;
|
||||
}
|
||||
if (pr->strref_hash) {
|
||||
Hash_FlushTable (pr->strref_hash);
|
||||
} else {
|
||||
|
@ -138,7 +175,7 @@ PR_LoadStrings (progs_t *pr)
|
|||
|
||||
if (pr->static_strings)
|
||||
free (pr->static_strings);
|
||||
pr->static_strings = calloc (count, sizeof (strref_t));
|
||||
pr->static_strings = malloc (count * sizeof (strref_t));
|
||||
count = 0;
|
||||
str = pr->pr_strings;
|
||||
while (str < end) {
|
||||
|
@ -198,8 +235,8 @@ PR_GarbageCollect (progs_t *pr)
|
|||
}
|
||||
}
|
||||
|
||||
static inline char *
|
||||
get_string (progs_t *pr, int num)
|
||||
static inline strref_t *
|
||||
get_strref (progs_t *pr, int num)
|
||||
{
|
||||
if (num < 0) {
|
||||
unsigned int row = ~num / 1024;
|
||||
|
@ -208,7 +245,22 @@ get_string (progs_t *pr, int num)
|
|||
|
||||
if (row >= pr->dyn_str_size)
|
||||
return 0;
|
||||
return pr->dynamic_strings[row][num].string;
|
||||
return &pr->dynamic_strings[row][num];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
get_string (progs_t *pr, int num)
|
||||
{
|
||||
if (num < 0) {
|
||||
strref_t *ref = get_strref (pr, num);
|
||||
if (!ref)
|
||||
return 0;
|
||||
if (ref->dstring)
|
||||
return ref->dstring->str;
|
||||
return ref->string;
|
||||
} else {
|
||||
if (num >= pr->pr_stringsize)
|
||||
return 0;
|
||||
|
@ -225,24 +277,95 @@ PR_StringValid (progs_t *pr, int num)
|
|||
const char *
|
||||
PR_GetString (progs_t *pr, int num)
|
||||
{
|
||||
char *str;
|
||||
const char *str;
|
||||
|
||||
str = get_string (pr, num);
|
||||
if (str)
|
||||
return str;
|
||||
PR_RunError (pr, "Invalid string offset %u", num);
|
||||
PR_RunError (pr, "Invalid string offset %d", num);
|
||||
}
|
||||
|
||||
dstring_t *
|
||||
PR_GetDString (progs_t *pr, int num)
|
||||
{
|
||||
strref_t *ref = get_strref (pr, num);
|
||||
if (ref) {
|
||||
if (ref->dstring)
|
||||
return ref->dstring;
|
||||
PR_RunError (pr, "not a dstring: %d", num);
|
||||
}
|
||||
PR_RunError (pr, "Invalid string offset: %d", num);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
pr_strdup (progs_t *pr, const char *s)
|
||||
{
|
||||
size_t len = strlen (s) + 1;
|
||||
char *new = PR_Zone_Malloc (pr, len);
|
||||
strcpy (new, s);
|
||||
return new;
|
||||
}
|
||||
|
||||
int
|
||||
PR_SetString (progs_t *pr, const char *s)
|
||||
{
|
||||
strref_t *sr = Hash_Find (pr->strref_hash, s);
|
||||
strref_t *sr = Hash_Find (pr->strref_hash, s);
|
||||
|
||||
if (!sr) {
|
||||
sr = new_string_ref (pr);
|
||||
sr->string = strdup(s);
|
||||
sr->string = pr_strdup(pr, s);
|
||||
sr->count = 0;
|
||||
Hash_Add (pr->strref_hash, sr);
|
||||
}
|
||||
return string_index (pr, sr);
|
||||
}
|
||||
|
||||
int
|
||||
PR_SetTempString (progs_t *pr, const char *s)
|
||||
{
|
||||
strref_t *sr;
|
||||
|
||||
sr = new_string_ref (pr);
|
||||
sr->string = pr_strdup(pr, s);
|
||||
sr->count = 0;
|
||||
sr->next = pr->pr_xtstr;
|
||||
pr->pr_xtstr = sr;
|
||||
return string_index (pr, sr);
|
||||
}
|
||||
|
||||
int
|
||||
PR_NewString (progs_t *pr)
|
||||
{
|
||||
strref_t *sr = new_string_ref (pr);
|
||||
sr->dstring = _dstring_newstr (pr->ds_mem);
|
||||
return string_index (pr, sr);
|
||||
}
|
||||
|
||||
void
|
||||
PR_FreeString (progs_t *pr, int str)
|
||||
{
|
||||
strref_t *sr = get_strref (pr, str);
|
||||
|
||||
if (sr) {
|
||||
if (sr->dstring)
|
||||
dstring_delete (sr->dstring);
|
||||
else
|
||||
PR_Zone_Free (pr, sr->string);
|
||||
free_string_ref (pr, sr);
|
||||
return;
|
||||
}
|
||||
PR_RunError (pr, "attempt to free invalid string %d", str);
|
||||
}
|
||||
|
||||
void
|
||||
PR_FreeTempStrings (progs_t *pr)
|
||||
{
|
||||
strref_t *sr, *t;
|
||||
|
||||
for (sr = pr->pr_xtstr; sr; sr = t) {
|
||||
t = sr->next;
|
||||
PR_Zone_Free (pr, sr->string);
|
||||
free_string_ref (pr, sr);
|
||||
}
|
||||
pr->pr_xtstr = 0;
|
||||
}
|
||||
|
|
|
@ -140,13 +140,8 @@ load_progs (const char *name)
|
|||
pr.progs_name = name;
|
||||
PR_LoadProgsFile (&pr, file, size, 1, 1024 * 1024);
|
||||
Qclose (file);
|
||||
if (!PR_ResolveGlobals (&pr))
|
||||
if (!PR_RunLoadFuncs (&pr))
|
||||
PR_Error (&pr, "unable to load %s", pr.progs_name);
|
||||
PR_LoadStrings (&pr);
|
||||
PR_LoadDebug (&pr);
|
||||
PR_Check_Opcodes (&pr);
|
||||
PR_RelocateBuiltins (&pr);
|
||||
PR_InitRuntime (&pr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
void () test_str =
|
||||
{
|
||||
local string a,b,c,d;
|
||||
a = "testing ";
|
||||
b = "temp ";
|
||||
c = "strings ";
|
||||
d = "\n";
|
||||
print (a + b + c + d);
|
||||
};
|
||||
|
||||
integer (integer argc, string []argv) main =
|
||||
{
|
||||
local integer i;
|
||||
|
@ -35,5 +45,6 @@ integer (integer argc, string []argv) main =
|
|||
print ("Object instances do not repond to `run:with:me:'\n");
|
||||
} else
|
||||
print ("did not find selector for `run:with:me:'\n");
|
||||
test_str ();
|
||||
return 0;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue