diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 0e9fa60c..bc3235fd 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -745,6 +745,7 @@ SC_FUNC void invoke_getter(struct methodmap_method_s *method); SC_FUNC void invoke_setter(struct methodmap_method_s *method, int save); SC_FUNC void inc_pri(); SC_FUNC void dec_pri(); +SC_FUNC void load_hidden_arg(); /* Code generation functions for arithmetic operators. * diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 6f07e61d..fbe1983b 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -7466,6 +7466,18 @@ static symbol *fetchlab(char *name) return sym; } +static int is_variadic(symbol *sym) +{ + assert(sym->ident==iFUNCTN); + arginfo *arg = sym->dim.arglist; + while (arg->ident) { + if (arg->ident == iVARARGS) + return TRUE; + arg++; + } + return FALSE; +} + /* doreturn * * Global references: rettype (altered) @@ -7574,7 +7586,11 @@ static void doreturn(void) * it stays on the heap for the moment, and it is removed -usually- at * the end of the expression/statement, see expression() in SC3.C) */ - address(sub,sALT); /* ALT = destination */ + if (!is_variadic(curfunc)) { + address(sub,sALT); /* ALT = destination */ + } else { + load_hidden_arg(); + } arraysize=calc_arraysize(dim,numdim,0); memcopy(arraysize*sizeof(cell)); /* source already in PRI */ /* moveto1(); is not necessary, callfunction() does a popreg() */ diff --git a/sourcepawn/compiler/sc4.c b/sourcepawn/compiler/sc4.c index 70c6f06f..0b00cc5e 100644 --- a/sourcepawn/compiler/sc4.c +++ b/sourcepawn/compiler/sc4.c @@ -34,6 +34,7 @@ static int fcurseg; /* the file number (fcurrent) for the active segment */ +SC_FUNC void load_i(); /* When a subroutine returns to address 0, the AMX must halt. In earlier * releases, the RET and RETN opcodes checked for the special case 0 address. @@ -391,8 +392,7 @@ SC_FUNC void rvalue(value *lval) sym=lval->sym; if (lval->ident==iARRAYCELL) { /* indirect fetch, address already in PRI */ - stgwrite("\tload.i\n"); - code_idx+=opcodes(1); + load_i(); } else if (lval->ident==iARRAYCHAR) { /* indirect fetch of a character from a pack, address already in PRI */ stgwrite("\tlodb.i "); @@ -469,6 +469,82 @@ SC_FUNC void address(symbol *sym,regid reg) code_idx+=opcodes(1)+opargs(1); } +// Compute an address to the storage slot of a local variable. +SC_FUNC void address_slot(symbol *sym, regid reg) +{ + assert(sym->vclass==sLOCAL); + switch (reg) { + case sPRI: + stgwrite("\taddr.pri "); + break; + case sALT: + stgwrite("\taddr.alt "); + break; + } /* switch */ + outval(sym->addr,TRUE); + markusage(sym,uREAD); + code_idx+=opcodes(1)+opargs(1); +} + +static void addr_reg(int val, regid reg) +{ + if (reg == sPRI) + stgwrite("\taddr.pri "); + else + stgwrite("\taddr.alt "); + outval(val, TRUE); + code_idx += opcodes(1) + opargs(1); +} + +// Load the number of arguments into PRI. Frame layout: +// base + 0*sizeof(cell) == previous "base" +// base + 1*sizeof(cell) == function return address +// base + 2*sizeof(cell) == number of arguments +// base + 3*sizeof(cell) == first argument of the function +static void load_argcount(regid reg) +{ + if (reg == sPRI) + stgwrite("\tload.s.pri "); + else + stgwrite("\tload.s.alt "); + outval(2 * sizeof(cell), TRUE); + code_idx += opcodes(1) + opargs(1); +} + +// PRI = ALT + (PRI * cellsize) +SC_FUNC void idxaddr() +{ + stgwrite("\tidxaddr\n"); + code_idx += opcodes(1); +} + +SC_FUNC void load_i() +{ + stgwrite("\tload.i\n"); + code_idx+=opcodes(1); +} + +// Load the hidden array argument into ALT. +SC_FUNC void load_hidden_arg() +{ + pushreg(sPRI); + + // Compute an address to the first argument, then add the argument count + // to find the address after the final argument: + // addr.alt 0xc ; Compute &first_arg + // load.s.alt 0x8 ; Load arg count + // idxaddr ; Compute (&first_arg) + argcount + // load.i ; Load *(&first_arg + argcount) + // move.alt ; Move result into ALT. + addr_reg(0xc, sALT); + load_argcount(sPRI); + idxaddr(); + load_i(); + move_alt(); + + popreg(sPRI); +} + /* store * * Saves the contents of "primary" into a memory cell, either directly