1.1 --- a/sourcepawn/compiler/amx.h Mon Aug 28 16:33:01 2006 +0000
1.2 +++ b/sourcepawn/compiler/amx.h Thu Sep 14 05:34:02 2006 +0000
1.3 @@ -619,6 +619,7 @@
1.4 OP_SYSREQ_D,
1.5 OP_SYSREQ_ND,
1.6 /* ----- */
1.7 + OP_HEAP_I,
1.8 OP_NUM_OPCODES
1.9 } OPCODE;
1.10
2.1 --- a/sourcepawn/compiler/sc.h Mon Aug 28 16:33:01 2006 +0000
2.2 +++ b/sourcepawn/compiler/sc.h Thu Sep 14 05:34:02 2006 +0000
2.3 @@ -602,6 +602,7 @@
2.4 SC_FUNC void modstk(int delta);
2.5 SC_FUNC void setstk(cell value);
2.6 SC_FUNC void modheap(int delta);
2.7 +SC_FUNC void modheap_i();
2.8 SC_FUNC void setheap_pri(void);
2.9 SC_FUNC void setheap(cell value);
2.10 SC_FUNC void cell2addr(void);
2.11 @@ -610,6 +611,7 @@
2.12 SC_FUNC void char2addr(void);
2.13 SC_FUNC void charalign(void);
2.14 SC_FUNC void addconst(cell value);
2.15 +SC_FUNC void setheap_save(cell value);
2.16
2.17 /* Code generation functions for arithmetic operators.
2.18 *
3.1 --- a/sourcepawn/compiler/sc3.c Mon Aug 28 16:33:01 2006 +0000
3.2 +++ b/sourcepawn/compiler/sc3.c Thu Sep 14 05:34:02 2006 +0000
3.3 @@ -60,9 +60,104 @@
3.4 static int commutative(void (*oper)());
3.5 static int constant(value *lval);
3.6
3.7 +#define HEAPUSE_STATIC 0
3.8 +#define HEAPUSE_DYNAMIC 1
3.9 +
3.10 +typedef struct heapuse_s {
3.11 + int type; /* HEAPUSE_STATIC or HEAPUSE_DYNAMIC */
3.12 + int size; /* size of array for static (0 for dynamic) */
3.13 + struct heapuse_s *prev; /* previous array on the list */
3.14 +} heapuse_t;
3.15 +
3.16 +typedef struct heapuse_list_s {
3.17 + struct heapuse_list_s *prev; /* last used list */
3.18 + heapuse_t *head; /* head of the current list */
3.19 +} heapuse_list_t;
3.20 +
3.21 static char lastsymbol[sNAMEMAX+1]; /* name of last function/variable */
3.22 static int bitwise_opercount; /* count of bitwise operators in an expression */
3.23 -static int decl_heap=0;
3.24 +//static int decl_heap=0;
3.25 +static heapuse_list_t *heapusage = NULL;
3.26 +
3.27 +/**
3.28 + * Creates a new heap allocation tracker entry
3.29 + */
3.30 +void pushheaplist()
3.31 +{
3.32 + heapuse_list_t *newlist=(heapuse_list_t *)malloc(sizeof(heapuse_list_t));
3.33 + newlist->prev=heapusage;
3.34 + newlist->head=NULL;
3.35 + heapusage=newlist;
3.36 +}
3.37 +
3.38 +/**
3.39 + * Generates code to free all heap allocations on a tracker
3.40 + */
3.41 +void freeheapusage(heapuse_list_t *heap)
3.42 +{
3.43 + heapuse_t *cur=heap->head;
3.44 + heapuse_t *tmp;
3.45 + while (cur) {
3.46 + if (cur->type == HEAPUSE_STATIC) {
3.47 + modheap((-1)*cur->size*sizeof(cell));
3.48 + } else {
3.49 + modheap_i();
3.50 + }
3.51 + tmp=cur->prev;
3.52 + free(cur);
3.53 + cur=tmp;
3.54 + }
3.55 + heap->head=NULL;
3.56 +}
3.57 +
3.58 +/**
3.59 + * Pops a heap list but does not free it.
3.60 + */
3.61 +heapuse_list_t *popsaveheaplist()
3.62 +{
3.63 + heapuse_list_t *oldlist=heapusage;
3.64 + heapusage=heapusage->prev;
3.65 + return oldlist;
3.66 +}
3.67 +
3.68 +/**
3.69 + * Pops a heap list and frees it.
3.70 + */
3.71 +void popheaplist()
3.72 +{
3.73 + heapuse_list_t *oldlist;
3.74 + assert(heapusage!=NULL);
3.75 +
3.76 + freeheapusage(heapusage);
3.77 + assert(heapusage->head==NULL);
3.78 +
3.79 + oldlist=heapusage->prev;
3.80 + free(heapusage);
3.81 + heapusage=oldlist;
3.82 +}
3.83 +
3.84 +/*
3.85 + * Returns the size passed in
3.86 + */
3.87 +int markheap(int type, int size)
3.88 +{
3.89 + heapuse_t *use;
3.90 + if (type==HEAPUSE_STATIC && size==0)
3.91 + return 0;
3.92 + use=heapusage->head;
3.93 + if (use && (type==HEAPUSE_STATIC)
3.94 + && (use->type == type))
3.95 + {
3.96 + use->size += size;
3.97 + } else {
3.98 + use=(heapuse_t *)malloc(sizeof(heapuse_t));
3.99 + use->type=type;
3.100 + use->size=size;
3.101 + use->prev=heapusage->head;
3.102 + heapusage->head=use;
3.103 + }
3.104 + return size;
3.105 +}
3.106
3.107 /* Function addresses of binary operators for signed operations */
3.108 static void (*op1[17])(void) = {
3.109 @@ -684,15 +779,13 @@
3.110
3.111 SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult)
3.112 {
3.113 - int locheap=decl_heap;
3.114 value lval={0};
3.115 + pushheaplist();
3.116
3.117 if (hier14(&lval))
3.118 rvalue(&lval);
3.119 /* scrap any arrays left on the heap */
3.120 - assert(decl_heap>=locheap);
3.121 - modheap((locheap-decl_heap)*sizeof(cell)); /* remove heap space, so negative delta */
3.122 - decl_heap=locheap;
3.123 + popheaplist();
3.124
3.125 if (lval.ident==iCONSTEXPR && val!=NULL) /* constant expression */
3.126 *val=lval.constval;
3.127 @@ -1047,6 +1140,34 @@
3.128 return FALSE; /* expression result is never an lvalue */
3.129 }
3.130
3.131 +/**
3.132 + * Sums up array usage in the current heap tracer and convert it into a dynamic array.
3.133 + * This is used for the ternary operator, which needs to convert its array usage into
3.134 + * something dynamically managed.
3.135 + * !Note:
3.136 + * This might break if expressions can ever return dynamic arrays.
3.137 + * Thus, we assert() if something is non-static here.
3.138 + * Right now, this poses no problem because this type of expression is impossible:
3.139 + * (a() ? return_array() : return_array()) ? return_array() : return_array()
3.140 + */
3.141 +
3.142 +void dynarray_from_heaplist(heapuse_list_t *heap)
3.143 +{
3.144 + heapuse_t *use=heap->head;
3.145 + heapuse_t *tmp;
3.146 + long total=0;
3.147 + while (use) {
3.148 + assert(use->type==HEAPUSE_STATIC);
3.149 + total+=use->size;
3.150 + tmp=use->prev;
3.151 + free(use);
3.152 + use=tmp;
3.153 + }
3.154 + free(heap);
3.155 + if (total)
3.156 + setheap_save(total);
3.157 +}
3.158 +
3.159 static int hier13(value *lval)
3.160 {
3.161 int lvalue=plnge1(hier12,lval);
3.162 @@ -1055,7 +1176,9 @@
3.163 int flab2=getlabel();
3.164 value lval2={0};
3.165 int array1,array2;
3.166 -
3.167 + heapuse_list_t *heap;
3.168 +
3.169 + pushheaplist();
3.170 if (lvalue) {
3.171 rvalue(lval);
3.172 } else if (lval->ident==iCONSTEXPR) {
3.173 @@ -1072,6 +1195,9 @@
3.174 sc_allowtags=(short)POPSTK_I(); /* restore */
3.175 jumplabel(flab2);
3.176 setlabel(flab1);
3.177 + heap=popsaveheaplist();
3.178 + dynarray_from_heaplist(heap);
3.179 + pushheaplist();
3.180 needtoken(':');
3.181 if (hier13(&lval2))
3.182 rvalue(&lval2);
3.183 @@ -1090,6 +1216,11 @@
3.184 if (!matchtag(lval->tag,lval2.tag,FALSE))
3.185 error(213); /* tagname mismatch ('true' and 'false' expressions) */
3.186 setlabel(flab2);
3.187 + heap=popsaveheaplist();
3.188 + dynarray_from_heaplist(heap);
3.189 + if (array1 && array2) {
3.190 + markheap(HEAPUSE_DYNAMIC, 0);
3.191 + }
3.192 if (lval->ident==iARRAY)
3.193 lval->ident=iREFARRAY; /* iARRAY becomes iREFARRAY */
3.194 else if (lval->ident!=iREFARRAY)
3.195 @@ -1871,6 +2002,7 @@
3.196 */
3.197 assert(array_sz>=size);
3.198 modheap((int)array_sz*sizeof(cell));
3.199 + markheap(HEAPUSE_STATIC, array_sz);
3.200 /* ??? should perhaps fill with zeros first */
3.201 memcopy(size*sizeof(cell));
3.202 moveto1();
3.203 @@ -1914,7 +2046,6 @@
3.204 {
3.205 static long nest_stkusage=0L;
3.206 static int nesting=0;
3.207 - int locheap;
3.208 int close,lvalue;
3.209 int argpos; /* index in the output stream (argpos==nargs if positional parameters) */
3.210 int argidx=0; /* index in "arginfo" list */
3.211 @@ -1946,12 +2077,12 @@
3.212 assert(retsize>0);
3.213 modheap(retsize*sizeof(cell));/* address is in ALT */
3.214 pushreg(sALT); /* pass ALT as the last (hidden) parameter */
3.215 - decl_heap+=retsize;
3.216 + markheap(HEAPUSE_STATIC, retsize);
3.217 /* also mark the ident of the result as "array" */
3.218 lval_result->ident=iREFARRAY;
3.219 lval_result->sym=symret;
3.220 } /* if */
3.221 - locheap=decl_heap;
3.222 + pushheaplist();
3.223
3.224 nesting++;
3.225 assert(nest_stkusage>=0);
3.226 @@ -2054,14 +2185,14 @@
3.227 } else {
3.228 rvalue(&lval); /* get value in PRI */
3.229 setheap_pri(); /* address of the value on the heap in PRI */
3.230 - heapalloc++;
3.231 + heapalloc+=markheap(HEAPUSE_STATIC, 1);
3.232 nest_stkusage++;
3.233 } /* if */
3.234 } else if (lvalue) {
3.235 address(lval.sym,sPRI);
3.236 } else {
3.237 setheap_pri(); /* address of the value on the heap in PRI */
3.238 - heapalloc++;
3.239 + heapalloc+=markheap(HEAPUSE_STATIC, 1);
3.240 nest_stkusage++;
3.241 } /* if */
3.242 } else if (lval.ident==iCONSTEXPR || lval.ident==iEXPRESSION
3.243 @@ -2073,7 +2204,7 @@
3.244 /* allocate a cell on the heap and store the
3.245 * value (already in PRI) there */
3.246 setheap_pri(); /* address of the value on the heap in PRI */
3.247 - heapalloc++;
3.248 + heapalloc+=markheap(HEAPUSE_STATIC, 1);
3.249 nest_stkusage++;
3.250 } /* if */
3.251 /* ??? handle const array passed by reference */
3.252 @@ -2111,7 +2242,7 @@
3.253 address(lval.sym,sPRI);
3.254 } else {
3.255 setheap_pri(); /* address of the value on the heap in PRI */
3.256 - heapalloc++;
3.257 + heapalloc+=markheap(HEAPUSE_STATIC, 1);
3.258 nest_stkusage++;
3.259 } /* if */
3.260 } /* if */
3.261 @@ -2258,7 +2389,7 @@
3.262 } else if (arg[argidx].ident==iREFERENCE) {
3.263 setheap(arg[argidx].defvalue.val);
3.264 /* address of the value on the heap in PRI */
3.265 - heapalloc++;
3.266 + heapalloc+=markheap(HEAPUSE_STATIC, 1);
3.267 nest_stkusage++;
3.268 } else {
3.269 int dummytag=arg[argidx].tags[0];
3.270 @@ -2329,7 +2460,6 @@
3.271 markusage(sym,uREAD); /* do not mark as "used" when this call itself is skipped */
3.272 if ((sym->usage & uNATIVE)!=0 &&sym->x.lib!=NULL)
3.273 sym->x.lib->value += 1; /* increment "usage count" of the library */
3.274 - modheap(-heapalloc*sizeof(cell));
3.275 if (symret!=NULL)
3.276 popreg(sPRI); /* pop hidden parameter as function result */
3.277 sideeffect=TRUE; /* assume functions carry out a side-effect */
3.278 @@ -2339,7 +2469,7 @@
3.279 /* maintain max. amount of memory used */
3.280 {
3.281 long totalsize;
3.282 - totalsize=declared+decl_heap+1; /* local variables & return value size,
3.283 + totalsize=declared+heapalloc+1; /* local variables & return value size,
3.284 * +1 for PROC opcode */
3.285 if (lval_result->ident==iREFARRAY)
3.286 totalsize++; /* add hidden parameter (on the stack) */
3.287 @@ -2361,9 +2491,7 @@
3.288 * this function has as a result (in other words, scrap all arrays on the
3.289 * heap that caused by expressions in the function arguments)
3.290 */
3.291 - assert(decl_heap>=locheap);
3.292 - modheap((locheap-decl_heap)*sizeof(cell)); /* remove heap space, so negative delta */
3.293 - decl_heap=locheap;
3.294 + popheaplist();
3.295 nesting--;
3.296 }
3.297
4.1 --- a/sourcepawn/compiler/sc4.c Mon Aug 28 16:33:01 2006 +0000
4.2 +++ b/sourcepawn/compiler/sc4.c Thu Sep 14 05:34:02 2006 +0000
4.3 @@ -844,6 +844,26 @@
4.4 } /* if */
4.5 }
4.6
4.7 +SC_FUNC void modheap_i()
4.8 +{
4.9 + stgwrite("\theap.i\n");
4.10 + code_idx+=opcodes(1);
4.11 +}
4.12 +
4.13 +SC_FUNC void setheap_save(cell value)
4.14 +{
4.15 + pushreg(sPRI);
4.16 + pushreg(sALT);
4.17 + stgwrite("\tconst.pri ");
4.18 + outval(value, TRUE);
4.19 + code_idx+=opcodes(1)+opargs(1);
4.20 + stgwrite("\theap ");
4.21 + outval(sizeof(cell), TRUE);
4.22 + stgwrite("\tstor.pri\n");
4.23 + popreg(sALT);
4.24 + popreg(sPRI);
4.25 +}
4.26 +
4.27 SC_FUNC void setheap_pri(void)
4.28 {
4.29 stgwrite("\theap "); /* ALT = HEA++ */
5.1 --- a/sourcepawn/compiler/sc6.c Mon Aug 28 16:33:01 2006 +0000
5.2 +++ b/sourcepawn/compiler/sc6.c Thu Sep 14 05:34:02 2006 +0000
5.3 @@ -493,6 +493,7 @@
5.4 { 99, "grtr", sIN_CSEG, parm0 },
5.5 {120, "halt", sIN_CSEG, parm1 },
5.6 { 45, "heap", sIN_CSEG, parm1 },
5.7 + {160, "heap.i", sIN_CSEG, parm0 },
5.8 { 27, "idxaddr", sIN_CSEG, parm0 },
5.9 { 28, "idxaddr.b", sIN_CSEG, parm1 },
5.10 {109, "inc", sIN_CSEG, parm1 },