diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 05676716..92f613a5 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -590,6 +590,7 @@ SC_FUNC void moveto1(void); SC_FUNC void pushreg(regid reg); SC_FUNC void pushval(cell val); SC_FUNC void popreg(regid reg); +SC_FUNC void genarray(int dims); SC_FUNC void swap1(void); SC_FUNC void ffswitch(int label); SC_FUNC void ffcase(cell value,char *labelname,int newtable); diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 145b5e21..b04da88c 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -1667,7 +1667,7 @@ static void declglb(char *firstname,int firsttag,int fpublic,int fstatic,int fst ispublic=TRUE; /* implicitly public variable */ assert(!fstatic); } /* if */ - while (matchtoken('[')) { + while (matchtoken('[')) { ident=iARRAY; if (numdim == sDIMEN_MAX) { error(53); /* exceeding maximum number of dimensions */ @@ -1926,19 +1926,45 @@ static int declloc(int fstatic) */ if ((sym=findloc(name))!=NULL && sym->compound!=nestlevel || findglb(name,sGLOBAL)!=NULL) error(219,name); /* variable shadows another symbol */ - while (matchtoken('[')){ - ident=iARRAY; - if (numdim == sDIMEN_MAX) { - error(53); /* exceeding maximum number of dimensions */ - return ident; - } /* if */ - size=needsub(&idxtag[numdim],&enumroot); /* get size; size==0 for "var[]" */ - #if INT_MAX < LONG_MAX - if (size > INT_MAX) - error(105); /* overflow, exceeding capacity */ - #endif - dim[numdim++]=(int)size; - } /* while */ + if (matchtoken('[')) { + do { + ident=iARRAY; + if (numdim == sDIMEN_MAX) { + error(53); /* exceeding maximum number of dimensions */ + return ident; + } /* if */ + size=needsub(&idxtag[numdim],&enumroot); /* get size; size==0 for "var[]" */ + #if INT_MAX < LONG_MAX + if (size > INT_MAX) + error(105); /* overflow, exceeding capacity */ + #endif + dim[numdim++]=(int)size; + } while (matchtoken('[')); + } else if (matchtoken('(')) { + int dim_ident; + int dim_tag; + symbol *dim_sym; + do { + ident=iREFARRAY; + if (numdim == sDIMEN_MAX) { + error(53); + return iREFARRAY; + } /* if */ + dim_ident = doexpr(TRUE,FALSE,FALSE,FALSE,&dim_tag,&dim_sym,0); + dim[numdim++] = 1; + if (dim_ident == iVARIABLE || dim_ident == iEXPRESSION) { + pushreg(sPRI); + } else if (dim_ident == iCONSTEXPR) { + pushreg(sPRI); + } else { + assert(0); //:TODO: make this an error + } + if (!matchtag(tag, dim_tag, FALSE)) + error(213); + needtoken(')'); + } while (matchtoken('(')); + genarray(numdim); + } if (getstates(name)) error(88,name); /* local variables may not have states */ if (ident==iARRAY || fstatic) { @@ -1952,7 +1978,7 @@ static int declloc(int fstatic) return ident; /* error message already given */ if (numdim==1) dim[0]=(int)size; - } /* if */ + } /* reserve memory (on the stack) for the variable */ if (fstatic) { /* write zeros for uninitialized fields */ @@ -1960,7 +1986,7 @@ static int declloc(int fstatic) litadd(0); sym=addvariable(name,(cur_lit+glb_declared)*sizeof(cell),ident,sSTATIC, tag,dim,numdim,idxtag); - } else { + } else if (ident!=iREFARRAY) { declared+=(int)size; /* variables are put on stack, adjust "declared" */ sym=addvariable(name,-declared*sizeof(cell),ident,sLOCAL,tag, dim,numdim,idxtag); @@ -1977,6 +2003,15 @@ static int declloc(int fstatic) assert((curfunc->usage & uNATIVE)==0); if (curfunc->x.stacksizex.stacksize=declared+1; /* +1 for PROC opcode */ + } else if (ident==iREFARRAY) { + declared+=1; /* one cell for address */ + sym=addvariable(name,-declared*sizeof(cell),ident,sLOCAL,tag,dim,numdim,idxtag); + //markexpr(sLDECL,name,-declared*sizeof(cell)); /* mark for better optimization */ + /* genarray() pushes the address onto the stack, so we don't need to call modstk() here! */ + markheap(MEMUSE_DYNAMIC, 0); + assert(curfunc != NULL && ((curfunc->usage & uNATIVE) == 0)); + if (curfunc->x.stacksizex.stacksize=declared+1; /* +1 for PROC opcode */ } /* if */ /* now that we have reserved memory for the variable, we can proceed * to initialize it */ @@ -2017,7 +2052,7 @@ static int declloc(int fstatic) * "uWRITTEN" flag that store() set */ if (!explicit_init) sym->usage &= ~uWRITTEN; - } else { + } else if (ident!=iREFARRAY) { /* an array */ assert(cur_lit>=0 && cur_lit<=litidx && litidx<=litmax); assert(size>0 && size>=sym->dim.array.length); @@ -3336,6 +3371,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc } /* if */ declared=0; /* number of local cells */ resetstacklist(); + resetheaplist(); rettype=(sym->usage & uRETVALUE); /* set "return type" variable */ curfunc=sym; define_args(); /* add the symbolic info for the function arguments */ @@ -4773,6 +4809,7 @@ static void compound(int stmt_sameline,int starttok) int endtok; pushstacklist(); + pushheaplist(); /* if there is more text on this line, we should adjust the statement indent */ if (stmt_sameline) { int i; @@ -4812,6 +4849,7 @@ static void compound(int stmt_sameline,int starttok) if (lastst!=tRETURN) destructsymbols(&loctab,nestlevel); if (lastst!=tRETURN && lastst!=tGOTO) { + popheaplist(); popstacklist(); } testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */ @@ -5506,6 +5544,7 @@ static void doreturn(void) rettype|=uRETNONE; /* function does not return anything */ } /* if */ destructsymbols(&loctab,0); /* call destructor for *all* locals */ + genheapfree(-1); genstackfree(-1); /* free everything on the stack */ ffret(strcmp(curfunc->name,uENTRYFUNC)!=0); } diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index f4d969af..834aeac5 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -672,6 +672,16 @@ SC_FUNC void popreg(regid reg) code_idx+=opcodes(1); } +/* + * Generate an array + */ +SC_FUNC void genarray(int dims) +{ + stgwrite("\tgenarray "); + outval(dims, TRUE); + code_idx+=opcodes(1)+opargs(1); +} + /* * swap the top-of-stack with the value in primary register */ @@ -846,13 +856,8 @@ SC_FUNC void modheap(int delta) SC_FUNC void modheap_i() { - pushreg(sPRI); - pushreg(sALT); - stgwrite("\tpop.h.pri\n"); - stgwrite("\theap.pri\n"); - code_idx+=opcodes(2); - popreg(sALT); - popreg(sPRI); + stgwrite("\theap.i\n"); + code_idx+=opcodes(1); } SC_FUNC void setheap_save(cell value) diff --git a/sourcepawn/compiler/sc6.c b/sourcepawn/compiler/sc6.c index 7539a09b..7dd4a295 100644 --- a/sourcepawn/compiler/sc6.c +++ b/sourcepawn/compiler/sc6.c @@ -489,11 +489,12 @@ static OPCODEC opcodelist[] = { {105, "eq.c.pri", sIN_CSEG, parm1 }, /*{124, "file", sIN_CSEG, do_file }, */ {119, "fill", sIN_CSEG, parm1 }, + {162, "genarray", sIN_CSEG, parm1 }, {100, "geq", sIN_CSEG, parm0 }, { 99, "grtr", sIN_CSEG, parm0 }, {120, "halt", sIN_CSEG, parm1 }, { 45, "heap", sIN_CSEG, parm1 }, - {160, "heap.pri", sIN_CSEG, parm0 }, + {160, "heap.i", sIN_CSEG, parm0 }, { 27, "idxaddr", sIN_CSEG, parm0 }, { 28, "idxaddr.b", sIN_CSEG, parm1 }, {109, "inc", sIN_CSEG, parm1 }, @@ -544,7 +545,6 @@ static OPCODEC opcodelist[] = { { 84, "not", sIN_CSEG, parm0 }, { 82, "or", sIN_CSEG, parm0 }, { 43, "pop.alt", sIN_CSEG, parm0 }, - {162, "pop.h.pri", sIN_CSEG, parm0 }, { 42, "pop.pri", sIN_CSEG, parm0 }, { 46, "proc", sIN_CSEG, parm0 }, { 40, "push", sIN_CSEG, parm1 }, diff --git a/sourcepawn/compiler/sctracker.c b/sourcepawn/compiler/sctracker.c index a5aa3127..b1d312e3 100644 --- a/sourcepawn/compiler/sctracker.c +++ b/sourcepawn/compiler/sctracker.c @@ -121,7 +121,7 @@ int markstack(int type, int size) /** * Generates code to free all heap allocations on a tracker */ -void _heap_freeusage(memuse_list_t *heap) +void _heap_freeusage(memuse_list_t *heap, int dofree) { memuse_t *cur=heap->head; memuse_t *tmp; @@ -133,11 +133,19 @@ void _heap_freeusage(memuse_list_t *heap) } else { modheap_i(); } - tmp=cur->prev; - free(cur); - cur=tmp; + if (dofree) + { + tmp=cur->prev; + free(cur); + cur=tmp; + } else { + cur=cur->prev; + } + } + if (dofree) + { + heap->head=NULL; } - heap->head=NULL; } void _stack_genusage(memuse_list_t *stack, int dofree) @@ -176,7 +184,7 @@ void popheaplist() memuse_list_t *oldlist; assert(heapusage!=NULL); - _heap_freeusage(heapusage); + _heap_freeusage(heapusage, 1); assert(heapusage->head==NULL); oldlist=heapusage->prev; @@ -194,6 +202,16 @@ void genstackfree(int stop_id) } } +void genheapfree(int stop_id) +{ + memuse_list_t *curlist = heapusage; + while (curlist && curlist->list_id > stop_id) + { + _heap_freeusage(curlist, 0); + curlist = curlist->prev; + } +} + void popstacklist() { memuse_list_t *oldlist; @@ -211,3 +229,8 @@ void resetstacklist() { _reset_memlist(&stackusage); } + +void resetheaplist() +{ + _reset_memlist(&heapusage); +} diff --git a/sourcepawn/compiler/sctracker.h b/sourcepawn/compiler/sctracker.h index 25be54ab..8cb02b72 100644 --- a/sourcepawn/compiler/sctracker.h +++ b/sourcepawn/compiler/sctracker.h @@ -31,16 +31,18 @@ void pushstacklist(); void popstacklist(); int markstack(int type, int size); /** - * Generates code to free stack usage, but does not pop the list. + * Generates code to free mem usage, but does not pop the list. * This is used for code like dobreak()/docont()/doreturn(). * stop_id is the list at which to stop generating. */ void genstackfree(int stop_id); +void genheapfree(int stop_id); /** - * Resets the stack list by freeing everything + * Resets a mem list by freeing everything */ void resetstacklist(); +void resetheaplist(); extern memuse_list_t *heapusage; extern memuse_list_t *stackusage;