1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-03 16:53:36 +03:00

Reduce the space allocated for the runtime virtual machine stack. (CVS 2428)

FossilOrigin-Name: 7d6818da33a87076d1faf35ffc15a3aada0533b3
This commit is contained in:
danielk1977
2005-03-29 08:26:13 +00:00
parent 53c0f7480b
commit bc04f8529d
8 changed files with 279 additions and 144 deletions

View File

@@ -166,6 +166,47 @@ void sqlite3VdbeResolveLabel(Vdbe *p, int x){
}
}
/*
** Return non-zero if opcode 'op' is guarenteed not to push more values
** onto the VDBE stack than it pops off.
*/
static int opcodeUsesStack(u8 op){
/* The 10 STACK_MASK_n constants are defined in the automatically
** generated header file opcodes.h. Each is a 16-bit bitmask, one
** bit corresponding to each opcode implemented by the virtual
** machine in vdbe.c. The bit is true if the word "stack" appears
** in a comment on the same line as the "case OP_XXX:" in
** sqlite3VdbeExec() in vdbe.c.
**
** If the bit is true, then the corresponding opcode is guarenteed not
** to grow the stack when it is executed. Otherwise, it may grow the
** stack by at most one entry.
**
** STACK_MASK_0 corresponds to opcodes 0 to 15. STACK_MASK_1 contains
** one bit for opcodes 16 to 31, and so on.
**
** 16-bit bitmasks (rather than 32-bit) are specified in opcodes.h
** because the file is generated by an awk program. Awk manipulates
** all numbers as floating-point and we don't want to risk a rounding
** error if someone builds with an awk that uses (for example) 32-bit
** IEEE floats.
*/
static u32 masks[5] = {
STACK_MASK_0 + (STACK_MASK_1<<16),
STACK_MASK_2 + (STACK_MASK_3<<16),
STACK_MASK_4 + (STACK_MASK_5<<16),
STACK_MASK_6 + (STACK_MASK_7<<16),
STACK_MASK_8 + (STACK_MASK_9<<16)
};
return (masks[op>>5] & (1<<(op&0x1F)));
}
#ifndef NDEBUG
int sqlite3VdbeOpcodeUsesStack(u8 op){
return opcodeUsesStack(op);
}
#endif
/*
** Loop through the program looking for P2 values that are negative.
** Each such value is a label. Resolve the label by setting the P2
@@ -176,22 +217,30 @@ void sqlite3VdbeResolveLabel(Vdbe *p, int x){
** Variable *pMaxFuncArgs is set to the maximum value of any P1 argument
** to an OP_Function or P2 to an OP_AggFunc opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
**
** The integer *pMaxStack is set to the maximum number of vdbe stack
** entries that static analysis reveals this program might need.
*/
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
int i;
int nMax = 0;
int nMaxArgs = 0;
int nMaxStack = p->nOp;
Op *pOp;
int *aLabel = p->aLabel;
if( aLabel==0 ) return;
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode;
/* Todo: Maybe OP_AggFunc should change to use P1 in the same
* way as OP_Function. */
* way as OP_Function.
*/
if( opcode==OP_Function ){
if( pOp->p1>nMax ) nMax = pOp->p1;
if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;
}else if( opcode==OP_AggFunc ){
if( pOp->p2>nMax ) nMax = pOp->p2;
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
}
if( opcodeUsesStack(opcode) ){
nMaxStack--;
}
if( pOp->p2>=0 ) continue;
@@ -200,7 +249,9 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
}
sqliteFree(p->aLabel);
p->aLabel = 0;
*pMaxFuncArgs = nMax;
*pMaxFuncArgs = nMaxArgs;
*pMaxStack = nMaxStack;
}
/*
@@ -641,12 +692,14 @@ void sqlite3VdbeMakeReady(
*/
if( p->aStack==0 ){
int nArg; /* Maximum number of args passed to a user function. */
resolveP2Values(p, &nArg);
int nStack; /* Maximum number of stack entries required */
resolveP2Values(p, &nArg, &nStack);
resizeOpArray(p, p->nOp);
assert( nVar>=0 );
n = isExplain ? 10 : p->nOp;
assert( nStack<p->nOp );
nStack = isExplain ? 10 : nStack;
p->aStack = sqliteMalloc(
n*sizeof(p->aStack[0]) /* aStack */
nStack*sizeof(p->aStack[0]) /* aStack */
+ nArg*sizeof(Mem*) /* apArg */
+ nVar*sizeof(Mem) /* aVar */
+ nVar*sizeof(char*) /* azVar */
@@ -655,7 +708,7 @@ void sqlite3VdbeMakeReady(
+ nAgg*sizeof(Agg) /* Aggregate contexts */
);
if( !sqlite3_malloc_failed ){
p->aMem = &p->aStack[n];
p->aMem = &p->aStack[nStack];
p->nMem = nMem;
p->aVar = &p->aMem[nMem];
p->nVar = nVar;