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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user