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

@@ -1,5 +1,5 @@
C Add\sthe\sSQLITE_OMIT_TEMPDB\scompile\stime\smacro.\s(CVS\s2427) C Reduce\sthe\sspace\sallocated\sfor\sthe\sruntime\svirtual\smachine\sstack.\s(CVS\s2428)
D 2005-03-29T03:10:59 D 2005-03-29T08:26:13
F Makefile.in 5c00d0037104de2a50ac7647a5f12769795957a3 F Makefile.in 5c00d0037104de2a50ac7647a5f12769795957a3
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -19,7 +19,7 @@ F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
F main.mk 3acc5ae52addd43fd1858fe99fca54a49bca6a56 F main.mk 3acc5ae52addd43fd1858fe99fca54a49bca6a56
F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512 F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
F mkopcodeh.awk e4d010870a3e98fd4323635c31565a3ca8584741 F mkopcodeh.awk d3d6dfcef5a7b69398627aec581d1ec52561517d
F mkso.sh 125868def279650a07d3f0f5e8476fecf99613fd F mkso.sh 125868def279650a07d3f0f5e8476fecf99613fd
F publish.sh ed0aba4ffdfadb36597d03ce8efdae96efc038cb F publish.sh ed0aba4ffdfadb36597d03ce8efdae96efc038cb
F spec.template b2f6c4e488cbc3b993a57deba22cbc36203c4da3 F spec.template b2f6c4e488cbc3b993a57deba22cbc36203c4da3
@@ -75,11 +75,11 @@ F src/update.c 42823d00865c9fe4f01b3c62647858726345a28e
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c 02bc2750336b021b3f10e61538f665c4b0033b5d F src/util.c 02bc2750336b021b3f10e61538f665c4b0033b5d
F src/vacuum.c 5cf598003191bd91c17a64742bad8e46241698a8 F src/vacuum.c 5cf598003191bd91c17a64742bad8e46241698a8
F src/vdbe.c e93a28aaa2a59c398ae243c2dc3b2da10cf1c5d2 F src/vdbe.c 68c8f34cbf7c05418c93e900d46f81b09500353a
F src/vdbe.h 7f586cb6d6b57764e5aac1f87107d6a95ddce24c F src/vdbe.h 7f586cb6d6b57764e5aac1f87107d6a95ddce24c
F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e F src/vdbeInt.h 39beecdfb017d3e042fe60974691abd573a5c5a2
F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac
F src/vdbeaux.c 0932f570d276992c7b3ee989589b6ff9056f97e7 F src/vdbeaux.c b28883d9efc9d4c1ec26c0d2473d5d8febc8178e
F src/vdbemem.c 4e853ce3151eaf7906150da85a1b3ce1fe5e8da8 F src/vdbemem.c 4e853ce3151eaf7906150da85a1b3ce1fe5e8da8
F src/where.c c4b227458e8993decb515ed9a2fe2d4f5f8e3125 F src/where.c c4b227458e8993decb515ed9a2fe2d4f5f8e3125
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
@@ -173,7 +173,7 @@ F test/pagesize.test 1b826d1608fd86d2303aa895b5586052ad07eba1
F test/pragma.test effcf2f0dea35223cbaa6bf40c47d0796ba39e40 F test/pragma.test effcf2f0dea35223cbaa6bf40c47d0796ba39e40
F test/printf.test 92ba4c510b4fc61120ffa4a01820446ed917ae57 F test/printf.test 92ba4c510b4fc61120ffa4a01820446ed917ae57
F test/progress.test 16496001da445e6534afb94562c286708316d82f x F test/progress.test 16496001da445e6534afb94562c286708316d82f x
F test/quick.test e9fdedf06bd06ff22fcbf6895c4f62fcbeb9e6b4 F test/quick.test a94d12658a2b590c1a5be580bef09bbb04c1266b
F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62 F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a
@@ -221,7 +221,7 @@ F tool/lemon.c c88936c67f6411608db8fa4254d254f509fa40f6
F tool/lempar.c e8b0eb00a6b905ce2ebd55965ed243574482cd5f F tool/lempar.c e8b0eb00a6b905ce2ebd55965ed243574482cd5f
F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133 F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133
F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8
F tool/memleak3.tcl 2b1ab290badf3b26f9ba433baf7fad8def14aea8 F tool/memleak3.tcl 009da0ea82dc5893edca76cf1a21fb7260e9412e
F tool/mkkeywordhash.c 02ac5c523fd6d55364cd70aded5c36ba6651a6bf F tool/mkkeywordhash.c 02ac5c523fd6d55364cd70aded5c36ba6651a6bf
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
@@ -278,7 +278,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
P 78df3d040443414ae5b440eeabc0c8c205ab311d P c41d55443c2dd532147962b87f542fb7d37075fd
R ab70e88fa1e907bd768a36809abb74cd R d1e86050613dbac2624d4c64006d314d
U danielk1977 U danielk1977
Z a20882d0dd8ba8be64666597fc85c766 Z d987ab454820e190643b62f4a4339773

View File

@@ -1 +1 @@
c41d55443c2dd532147962b87f542fb7d37075fd 7d6818da33a87076d1faf35ffc15a3aada0533b3

View File

@@ -24,6 +24,7 @@
# the total library smaller. # the total library smaller.
# #
# Remember the TK_ values from the parse.h file # Remember the TK_ values from the parse.h file
/^#define TK_/ { /^#define TK_/ {
tk[$2] = $3 tk[$2] = $3
@@ -35,11 +36,16 @@
gsub(/:/,"",name) gsub(/:/,"",name)
gsub("\r","",name) gsub("\r","",name)
op[name] = -1 op[name] = -1
for(i=3; i<NF-2; i++){ for(i=3; i<NF; i++){
if($i=="same" && $(i+1)=="as"){ if($i=="same" && $(i+1)=="as"){
op[name] = tk[$(i+2)] sym = $(i+2)
sub(/,/,"",sym)
op[name] = tk[sym]
used[op[name]] = 1 used[op[name]] = 1
sameas[op[name]] = $(i+2) sameas[op[name]] = sym
}
if($i=="stack"){
stack[name] = 1
} }
} }
} }
@@ -75,4 +81,31 @@ END {
printf "#define %-25s %15d\n", sprintf( "OP_NotUsed_%-3d", i ), i printf "#define %-25s %15d\n", sprintf( "OP_NotUsed_%-3d", i ), i
} }
} }
# Generate the 10 16-bit bitmasks used by function opcodeUsesStack()
# in vdbeaux.c. See comments in that function for details.
#
stack[0] = 0 # 0..15
stack[1] = 0 # 16..31
stack[2] = 0 # 32..47
stack[3] = 0 # 48..63
stack[4] = 0 # 64..79
stack[5] = 0 # 80..95
stack[6] = 0 # 96..111
stack[7] = 0 # 112..127
stack[8] = 0 # 128..143
stack[9] = 0 # 144..159
for(name in op){
if( stack[name] ){
n = op[name]
j = n%16
i = ((n - j)/16)
stack[i] = stack[i] + (2^j)
}
}
printf "\n"
for(i=0; i<10; i++){
printf "#define STACK_MASK_%d %d\n", i, stack[i]
}
} }

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.461 2005/03/29 03:11:00 danielk1977 Exp $ ** $Id: vdbe.c,v 1.462 2005/03/29 08:26:13 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -462,6 +462,9 @@ int sqlite3VdbeExec(
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
int nProgressOps = 0; /* Opcodes executed since progress callback. */ int nProgressOps = 0; /* Opcodes executed since progress callback. */
#endif #endif
#ifndef NDEBUG
Mem *pStackLimit;
#endif
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( db->magic==SQLITE_MAGIC_BUSY ); assert( db->magic==SQLITE_MAGIC_BUSY );
@@ -533,6 +536,23 @@ int sqlite3VdbeExec(
} }
#endif #endif
#ifndef NDEBUG
/* This is to check that the return value of static function
** opcodeUsesStack() (see vdbeaux.c) returns values that match the
** implementation of the virtual machine in this file. If
** opcodeUsesStack() returns non-zero, then the stack is guarenteed
** not to grow when the opcode is executed. If it returns zero, then
** the stack may grow by at most 1.
**
** The global wrapper function sqlite3VdbeOpcodeUsesStack() is not
** available if NDEBUG is defined at build time.
*/
pStackLimit = pTos;
if( !sqlite3VdbeOpcodeUsesStack(pOp->opcode) ){
pStackLimit++;
}
#endif
switch( pOp->opcode ){ switch( pOp->opcode ){
/***************************************************************************** /*****************************************************************************
@@ -553,6 +573,11 @@ int sqlite3VdbeExec(
** case statement is followed by a comment of the form "/# same as ... #/" ** case statement is followed by a comment of the form "/# same as ... #/"
** that comment is used to determine the particular value of the opcode. ** that comment is used to determine the particular value of the opcode.
** **
** If a comment on the same line as the "case OP_" construction contains
** the word "stack", then the opcode is guarenteed not to grow the
** vdbe stack when it is executed. See function opcodeUsesStack() in
** vdbeaux.c for details.
**
** Documentation about VDBE opcodes is generated by scanning this file ** Documentation about VDBE opcodes is generated by scanning this file
** for lines of that contain "Opcode:". That line and all subsequent ** for lines of that contain "Opcode:". That line and all subsequent
** comment lines are used in the generation of the opcode.html documentation ** comment lines are used in the generation of the opcode.html documentation
@@ -572,7 +597,7 @@ int sqlite3VdbeExec(
** the one at index P2 from the beginning of ** the one at index P2 from the beginning of
** the program. ** the program.
*/ */
case OP_Goto: { case OP_Goto: { /* no stack growth */
CHECK_FOR_INTERRUPT; CHECK_FOR_INTERRUPT;
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
break; break;
@@ -588,7 +613,7 @@ case OP_Goto: {
** the return address stack will fill up and processing will abort ** the return address stack will fill up and processing will abort
** with a fatal error. ** with a fatal error.
*/ */
case OP_Gosub: { case OP_Gosub: { /* no stack growth */
assert( p->returnDepth<sizeof(p->returnStack)/sizeof(p->returnStack[0]) ); assert( p->returnDepth<sizeof(p->returnStack)/sizeof(p->returnStack[0]) );
p->returnStack[p->returnDepth++] = pc+1; p->returnStack[p->returnDepth++] = pc+1;
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
@@ -601,7 +626,7 @@ case OP_Gosub: {
** OP_Gosub. If an OP_Return has occurred for all OP_Gosubs, then ** OP_Gosub. If an OP_Return has occurred for all OP_Gosubs, then
** processing aborts with a fatal error. ** processing aborts with a fatal error.
*/ */
case OP_Return: { case OP_Return: { /* no stack growth */
assert( p->returnDepth>0 ); assert( p->returnDepth>0 );
p->returnDepth--; p->returnDepth--;
pc = p->returnStack[p->returnDepth] - 1; pc = p->returnStack[p->returnDepth] - 1;
@@ -625,7 +650,7 @@ case OP_Return: {
** every program. So a jump past the last instruction of the program ** every program. So a jump past the last instruction of the program
** is the same as executing Halt. ** is the same as executing Halt.
*/ */
case OP_Halt: { case OP_Halt: { /* no stack growth */
p->pTos = pTos; p->pTos = pTos;
p->rc = pOp->p1; p->rc = pOp->p1;
p->pc = pc; p->pc = pc;
@@ -671,7 +696,7 @@ case OP_Integer: {
** **
** The string value P3 is converted to a real and pushed on to the stack. ** The string value P3 is converted to a real and pushed on to the stack.
*/ */
case OP_Real: { /* same as TK_FLOAT */ case OP_Real: { /* same as TK_FLOAT, */
pTos++; pTos++;
pTos->flags = MEM_Str|MEM_Static|MEM_Term; pTos->flags = MEM_Str|MEM_Static|MEM_Term;
pTos->z = pOp->p3; pTos->z = pOp->p3;
@@ -807,7 +832,7 @@ case OP_Variable: {
** **
** P1 elements are popped off of the top of stack and discarded. ** P1 elements are popped off of the top of stack and discarded.
*/ */
case OP_Pop: { case OP_Pop: { /* no stack growth */
assert( pOp->p1>=0 ); assert( pOp->p1>=0 );
popStack(&pTos, pOp->p1); popStack(&pTos, pOp->p1);
assert( pTos>=&p->aStack[-1] ); assert( pTos>=&p->aStack[-1] );
@@ -850,7 +875,7 @@ case OP_Dup: {
** **
** See also the Dup instruction. ** See also the Dup instruction.
*/ */
case OP_Pull: { case OP_Pull: { /* no stack growth */
Mem *pFrom = &pTos[-pOp->p1]; Mem *pFrom = &pTos[-pOp->p1];
int i; int i;
Mem ts; Mem ts;
@@ -882,7 +907,7 @@ case OP_Pull: {
** stack (P1==0 is the top of the stack) with the value ** stack (P1==0 is the top of the stack) with the value
** of the top of the stack. Then pop the top of the stack. ** of the top of the stack. Then pop the top of the stack.
*/ */
case OP_Push: { case OP_Push: { /* no stack growth */
Mem *pTo = &pTos[-pOp->p1]; Mem *pTo = &pTos[-pOp->p1];
assert( pTo>=p->aStack ); assert( pTo>=p->aStack );
@@ -897,7 +922,7 @@ case OP_Push: {
** invoke the callback function using the newly formed array as the ** invoke the callback function using the newly formed array as the
** 3rd parameter. ** 3rd parameter.
*/ */
case OP_Callback: { case OP_Callback: { /* no stack growth */
int i; int i;
assert( p->nResColumn==pOp->p1 ); assert( p->nResColumn==pOp->p1 );
@@ -1033,11 +1058,11 @@ case OP_Concat: { /* same as TK_CONCAT */
** function before the division. Division by zero returns NULL. ** function before the division. Division by zero returns NULL.
** If either operand is NULL, the result is NULL. ** If either operand is NULL, the result is NULL.
*/ */
case OP_Add: /* same as TK_PLUS */ case OP_Add: /* same as TK_PLUS, no stack growth */
case OP_Subtract: /* same as TK_MINUS */ case OP_Subtract: /* same as TK_MINUS, no stack growth */
case OP_Multiply: /* same as TK_STAR */ case OP_Multiply: /* same as TK_STAR, no stack growth */
case OP_Divide: /* same as TK_SLASH */ case OP_Divide: /* same as TK_SLASH, no stack growth */
case OP_Remainder: { /* same as TK_REM */ case OP_Remainder: { /* same as TK_REM, no stack growth */
Mem *pNos = &pTos[-1]; Mem *pNos = &pTos[-1];
assert( pNos>=p->aStack ); assert( pNos>=p->aStack );
if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){ if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
@@ -1117,7 +1142,7 @@ divide_by_zero:
** to retrieve the collation sequence set by this opcode is not available ** to retrieve the collation sequence set by this opcode is not available
** publicly, only to user functions defined in func.c. ** publicly, only to user functions defined in func.c.
*/ */
case OP_CollSeq: { case OP_CollSeq: { /* no stack growth */
assert( pOp->p3type==P3_COLLSEQ ); assert( pOp->p3type==P3_COLLSEQ );
break; break;
} }
@@ -1235,10 +1260,10 @@ case OP_Function: {
** right by N bits where N is the top element on the stack. ** right by N bits where N is the top element on the stack.
** If either operand is NULL, the result is NULL. ** If either operand is NULL, the result is NULL.
*/ */
case OP_BitAnd: /* same as TK_BITAND */ case OP_BitAnd: /* same as TK_BITAND, no stack growth */
case OP_BitOr: /* same as TK_BITOR */ case OP_BitOr: /* same as TK_BITOR, no stack growth */
case OP_ShiftLeft: /* same as TK_LSHIFT */ case OP_ShiftLeft: /* same as TK_LSHIFT, no stack growth */
case OP_ShiftRight: { /* same as TK_RSHIFT */ case OP_ShiftRight: { /* same as TK_RSHIFT, no stack growth */
Mem *pNos = &pTos[-1]; Mem *pNos = &pTos[-1];
int a, b; int a, b;
@@ -1273,7 +1298,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT */
** **
** To force the top of the stack to be an integer, just add 0. ** To force the top of the stack to be an integer, just add 0.
*/ */
case OP_AddImm: { case OP_AddImm: { /* no stack growth */
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
Integerify(pTos); Integerify(pTos);
pTos->i += pOp->p1; pTos->i += pOp->p1;
@@ -1290,7 +1315,7 @@ case OP_AddImm: {
** current value if P1==0, or to the least integer that is strictly ** current value if P1==0, or to the least integer that is strictly
** greater than its current value if P1==1. ** greater than its current value if P1==1.
*/ */
case OP_ForceInt: { case OP_ForceInt: { /* no stack growth */
int v; int v;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc); applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
@@ -1325,7 +1350,7 @@ case OP_ForceInt: {
** P1 is 1, then the stack is popped. In all other cases, the depth ** P1 is 1, then the stack is popped. In all other cases, the depth
** of the stack is unchanged. ** of the stack is unchanged.
*/ */
case OP_MustBeInt: { case OP_MustBeInt: { /* no stack growth */
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc); applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
if( (pTos->flags & MEM_Int)==0 ){ if( (pTos->flags & MEM_Int)==0 ){
@@ -1400,12 +1425,12 @@ case OP_MustBeInt: {
** the 2nd element down on the stack is greater than or equal to the ** the 2nd element down on the stack is greater than or equal to the
** top of the stack. See the Eq opcode for additional information. ** top of the stack. See the Eq opcode for additional information.
*/ */
case OP_Eq: /* same as TK_EQ */ case OP_Eq: /* same as TK_EQ, no stack growth */
case OP_Ne: /* same as TK_NE */ case OP_Ne: /* same as TK_NE, no stack growth */
case OP_Lt: /* same as TK_LT */ case OP_Lt: /* same as TK_LT, no stack growth */
case OP_Le: /* same as TK_LE */ case OP_Le: /* same as TK_LE, no stack growth */
case OP_Gt: /* same as TK_GT */ case OP_Gt: /* same as TK_GT, no stack growth */
case OP_Ge: { /* same as TK_GE */ case OP_Ge: { /* same as TK_GE, no stack growth */
Mem *pNos; Mem *pNos;
int flags; int flags;
int res; int res;
@@ -1471,8 +1496,8 @@ case OP_Ge: { /* same as TK_GE */
** two values and push the resulting boolean value back onto the ** two values and push the resulting boolean value back onto the
** stack. ** stack.
*/ */
case OP_And: /* same as TK_AND */ case OP_And: /* same as TK_AND, no stack growth */
case OP_Or: { /* same as TK_OR */ case OP_Or: { /* same as TK_OR, no stack growth */
Mem *pNos = &pTos[-1]; Mem *pNos = &pTos[-1];
int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */ int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
@@ -1519,7 +1544,7 @@ case OP_Or: { /* same as TK_OR */
** with its absolute value. If the top of the stack is NULL ** with its absolute value. If the top of the stack is NULL
** its value is unchanged. ** its value is unchanged.
*/ */
case OP_Negative: /* same as TK_UMINUS */ case OP_Negative: /* same as TK_UMINUS, no stack growth */
case OP_AbsValue: { case OP_AbsValue: {
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
if( pTos->flags & MEM_Real ){ if( pTos->flags & MEM_Real ){
@@ -1552,7 +1577,7 @@ case OP_AbsValue: {
** with its complement. If the top of the stack is NULL its value ** with its complement. If the top of the stack is NULL its value
** is unchanged. ** is unchanged.
*/ */
case OP_Not: { /* same as TK_NOT */ case OP_Not: { /* same as TK_NOT, no stack growth */
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
Integerify(pTos); Integerify(pTos);
@@ -1568,7 +1593,7 @@ case OP_Not: { /* same as TK_NOT */
** with its ones-complement. If the top of the stack is NULL its ** with its ones-complement. If the top of the stack is NULL its
** value is unchanged. ** value is unchanged.
*/ */
case OP_BitNot: { /* same as TK_BITNOT */ case OP_BitNot: { /* same as TK_BITNOT, no stack growth */
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
Integerify(pTos); Integerify(pTos);
@@ -1583,7 +1608,7 @@ case OP_BitNot: { /* same as TK_BITNOT */
** Do nothing. This instruction is often useful as a jump ** Do nothing. This instruction is often useful as a jump
** destination. ** destination.
*/ */
case OP_Noop: { case OP_Noop: { /* no stack growth */
break; break;
} }
@@ -1607,8 +1632,8 @@ case OP_Noop: {
** If the value popped of the stack is NULL, then take the jump if P1 ** If the value popped of the stack is NULL, then take the jump if P1
** is true and fall through if P1 is false. ** is true and fall through if P1 is false.
*/ */
case OP_If: case OP_If: /* no stack growth */
case OP_IfNot: { case OP_IfNot: { /* no stack growth */
int c; int c;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ){ if( pTos->flags & MEM_Null ){
@@ -1629,7 +1654,7 @@ case OP_IfNot: {
** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack ** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack
** unchanged. ** unchanged.
*/ */
case OP_IsNull: { /* same as TK_ISNULL */ case OP_IsNull: { /* same as TK_ISNULL, no stack growth */
int i, cnt; int i, cnt;
Mem *pTerm; Mem *pTerm;
cnt = pOp->p1; cnt = pOp->p1;
@@ -1652,7 +1677,7 @@ case OP_IsNull: { /* same as TK_ISNULL */
** stack if P1 times if P1 is greater than zero. If P1 is less than ** stack if P1 times if P1 is greater than zero. If P1 is less than
** zero then leave the stack unchanged. ** zero then leave the stack unchanged.
*/ */
case OP_NotNull: { /* same as TK_NOTNULL */ case OP_NotNull: { /* same as TK_NOTNULL, no stack growth */
int i, cnt; int i, cnt;
cnt = pOp->p1; cnt = pOp->p1;
if( cnt<0 ) cnt = -cnt; if( cnt<0 ) cnt = -cnt;
@@ -1673,7 +1698,7 @@ case OP_NotNull: { /* same as TK_NOTNULL */
** If OP_KeyAsData is to be applied to cursor P1, it must be executed ** If OP_KeyAsData is to be applied to cursor P1, it must be executed
** before this op-code. ** before this op-code.
*/ */
case OP_SetNumColumns: { case OP_SetNumColumns: { /* no stack growth */
Cursor *pC; Cursor *pC;
assert( (pOp->p1)<p->nCursor ); assert( (pOp->p1)<p->nCursor );
assert( p->apCsr[pOp->p1]!=0 ); assert( p->apCsr[pOp->p1]!=0 );
@@ -2131,7 +2156,7 @@ case OP_MakeRecord: {
** database file has an index of 0 and the file used for temporary tables ** database file has an index of 0 and the file used for temporary tables
** has an index of 1. ** has an index of 1.
*/ */
case OP_Statement: { case OP_Statement: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Btree *pBt; Btree *pBt;
if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){ if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){
@@ -2151,7 +2176,7 @@ case OP_Statement: {
** **
** This instruction causes the VM to halt. ** This instruction causes the VM to halt.
*/ */
case OP_AutoCommit: { case OP_AutoCommit: { /* no stack growth */
u8 i = pOp->p1; u8 i = pOp->p1;
u8 rollback = pOp->p2; u8 rollback = pOp->p2;
@@ -2212,7 +2237,7 @@ case OP_AutoCommit: {
** **
** If P2 is zero, then a read-lock is obtained on the database file. ** If P2 is zero, then a read-lock is obtained on the database file.
*/ */
case OP_Transaction: { case OP_Transaction: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Btree *pBt; Btree *pBt;
@@ -2275,7 +2300,7 @@ case OP_ReadCookie: {
** **
** A transaction must be started before executing this opcode. ** A transaction must be started before executing this opcode.
*/ */
case OP_SetCookie: { case OP_SetCookie: { /* no stack growth */
Db *pDb; Db *pDb;
assert( pOp->p2<SQLITE_N_BTREE_META ); assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( pOp->p1>=0 && pOp->p1<db->nDb );
@@ -2311,7 +2336,7 @@ case OP_SetCookie: {
** to be executed (to establish a read lock) before this opcode is ** to be executed (to establish a read lock) before this opcode is
** invoked. ** invoked.
*/ */
case OP_VerifyCookie: { case OP_VerifyCookie: { /* no stack growth */
int iMeta; int iMeta;
Btree *pBt; Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( pOp->p1>=0 && pOp->p1<db->nDb );
@@ -2371,8 +2396,8 @@ case OP_VerifyCookie: {
** **
** See also OpenRead. ** See also OpenRead.
*/ */
case OP_OpenRead: case OP_OpenRead: /* no stack growth */
case OP_OpenWrite: { case OP_OpenWrite: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
int p2 = pOp->p2; int p2 = pOp->p2;
int wrFlag; int wrFlag;
@@ -2460,7 +2485,7 @@ case OP_OpenWrite: {
** whereas "Temporary" in the context of CREATE TABLE means for the duration ** whereas "Temporary" in the context of CREATE TABLE means for the duration
** of the connection to the database. Same word; different meanings. ** of the connection to the database. Same word; different meanings.
*/ */
case OP_OpenTemp: { case OP_OpenTemp: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pCx; Cursor *pCx;
assert( i>=0 ); assert( i>=0 );
@@ -2509,7 +2534,7 @@ case OP_OpenTemp: {
** A pseudo-table created by this opcode is useful for holding the ** A pseudo-table created by this opcode is useful for holding the
** NEW or OLD tables in a trigger. ** NEW or OLD tables in a trigger.
*/ */
case OP_OpenPseudo: { case OP_OpenPseudo: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pCx; Cursor *pCx;
assert( i>=0 ); assert( i>=0 );
@@ -2527,7 +2552,7 @@ case OP_OpenPseudo: {
** Close a cursor previously opened as P1. If P1 is not ** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op. ** currently open, this instruction is a no-op.
*/ */
case OP_Close: { case OP_Close: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nCursor ){ if( i>=0 && i<p->nCursor ){
sqlite3VdbeFreeCursor(p->apCsr[i]); sqlite3VdbeFreeCursor(p->apCsr[i]);
@@ -2576,10 +2601,10 @@ case OP_Close: {
** **
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
*/ */
case OP_MoveLt: case OP_MoveLt: /* no stack growth */
case OP_MoveLe: case OP_MoveLe: /* no stack growth */
case OP_MoveGe: case OP_MoveGe: /* no stack growth */
case OP_MoveGt: { case OP_MoveGt: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
@@ -2688,9 +2713,9 @@ case OP_MoveGt: {
** **
** See also: Distinct, Found, MoveTo, NotExists, IsUnique ** See also: Distinct, Found, MoveTo, NotExists, IsUnique
*/ */
case OP_Distinct: case OP_Distinct: /* no stack growth */
case OP_NotFound: case OP_NotFound: /* no stack growth */
case OP_Found: { case OP_Found: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
int alreadyExists = 0; int alreadyExists = 0;
Cursor *pC; Cursor *pC;
@@ -2739,7 +2764,7 @@ case OP_Found: {
** **
** See also: Distinct, NotFound, NotExists, Found ** See also: Distinct, NotFound, NotExists, Found
*/ */
case OP_IsUnique: { case OP_IsUnique: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Mem *pNos = &pTos[-1]; Mem *pNos = &pTos[-1];
Cursor *pCx; Cursor *pCx;
@@ -2833,7 +2858,7 @@ case OP_IsUnique: {
** **
** See also: Distinct, Found, MoveTo, NotFound, IsUnique ** See also: Distinct, Found, MoveTo, NotFound, IsUnique
*/ */
case OP_NotExists: { case OP_NotExists: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
@@ -3036,8 +3061,8 @@ case OP_NewRecno: {
** **
** P1 may not be a pseudo-table opened using the OpenPseudo opcode. ** P1 may not be a pseudo-table opened using the OpenPseudo opcode.
*/ */
case OP_PutIntKey: case OP_PutIntKey: /* no stack growth */
case OP_PutStrKey: { case OP_PutStrKey: { /* no stack growth */
Mem *pNos = &pTos[-1]; Mem *pNos = &pTos[-1];
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
@@ -3131,7 +3156,7 @@ case OP_PutStrKey: {
** **
** If P1 is a pseudo-table, then this instruction is a no-op. ** If P1 is a pseudo-table, then this instruction is a no-op.
*/ */
case OP_Delete: { case OP_Delete: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
@@ -3155,7 +3180,7 @@ case OP_Delete: {
** change counter (returned by subsequent calls to sqlite3_changes()) ** change counter (returned by subsequent calls to sqlite3_changes())
** before it is reset. This is used by trigger programs. ** before it is reset. This is used by trigger programs.
*/ */
case OP_ResetCount: { case OP_ResetCount: { /* no stack growth */
if( pOp->p1 ){ if( pOp->p1 ){
sqlite3VdbeSetChanges(db, p->nChange); sqlite3VdbeSetChanges(db, p->nChange);
} }
@@ -3170,7 +3195,7 @@ case OP_ResetCount: {
** data off of the key rather than the data. This is used for ** data off of the key rather than the data. This is used for
** processing compound selects. ** processing compound selects.
*/ */
case OP_KeyAsData: { case OP_KeyAsData: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
@@ -3346,7 +3371,7 @@ case OP_FullKey: {
** that occur while the cursor is on the null row will always push ** that occur while the cursor is on the null row will always push
** a NULL onto the stack. ** a NULL onto the stack.
*/ */
case OP_NullRow: { case OP_NullRow: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
@@ -3366,7 +3391,7 @@ case OP_NullRow: {
** If P2 is 0 or if the table or index is not empty, fall through ** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction. ** to the following instruction.
*/ */
case OP_Last: { case OP_Last: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
@@ -3397,7 +3422,7 @@ case OP_Last: {
** If P2 is 0 or if the table or index is not empty, fall through ** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction. ** to the following instruction.
*/ */
case OP_Rewind: { case OP_Rewind: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
@@ -3437,8 +3462,8 @@ case OP_Rewind: {
** to the following instruction. But if the cursor backup was successful, ** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2. ** jump immediately to P2.
*/ */
case OP_Prev: case OP_Prev: /* no stack growth */
case OP_Next: { case OP_Next: { /* no stack growth */
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
@@ -3479,7 +3504,7 @@ case OP_Next: {
** is rolled back. If P3 is not null, then it becomes part of the ** is rolled back. If P3 is not null, then it becomes part of the
** error message returned with the SQLITE_CONSTRAINT. ** error message returned with the SQLITE_CONSTRAINT.
*/ */
case OP_IdxPut: { case OP_IdxPut: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
@@ -3531,7 +3556,7 @@ case OP_IdxPut: {
** The top of the stack is an index key built using the MakeIdxKey opcode. ** The top of the stack is an index key built using the MakeIdxKey opcode.
** This opcode removes that entry from the index. ** This opcode removes that entry from the index.
*/ */
case OP_IdxDelete: { case OP_IdxDelete: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
@@ -3633,9 +3658,9 @@ case OP_IdxRecno: {
** an epsilon prior to the comparison. This makes the opcode work ** an epsilon prior to the comparison. This makes the opcode work
** like IdxLE. ** like IdxLE.
*/ */
case OP_IdxLT: case OP_IdxLT: /* no stack growth */
case OP_IdxGT: case OP_IdxGT: /* no stack growth */
case OP_IdxGE: { case OP_IdxGE: { /* no stack growth */
int i= pOp->p1; int i= pOp->p1;
BtCursor *pCrsr; BtCursor *pCrsr;
Cursor *pC; Cursor *pC;
@@ -3679,7 +3704,7 @@ case OP_IdxGE: {
** **
** The index entry is always popped from the stack. ** The index entry is always popped from the stack.
*/ */
case OP_IdxIsNull: { case OP_IdxIsNull: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
int k, n; int k, n;
const char *z; const char *z;
@@ -3753,7 +3778,7 @@ case OP_Destroy: {
** **
** See also: Destroy ** See also: Destroy
*/ */
case OP_Clear: { case OP_Clear: { /* no stack growth */
rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1); rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break; break;
} }
@@ -3811,7 +3836,7 @@ case OP_CreateTable: {
** This opcode invokes the parser to create a new virtual machine, ** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a reentrant opcode. ** then runs the new virtual machine. It is thus a reentrant opcode.
*/ */
case OP_ParseSchema: { case OP_ParseSchema: { /* no stack growth */
char *zSql; char *zSql;
int iDb = pOp->p1; int iDb = pOp->p1;
const char *zMaster; const char *zMaster;
@@ -3843,7 +3868,7 @@ case OP_ParseSchema: {
** is dropped in order to keep the internal representation of the ** is dropped in order to keep the internal representation of the
** schema consistent with what is on disk. ** schema consistent with what is on disk.
*/ */
case OP_DropTable: { case OP_DropTable: { /* no stack growth */
sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p3); sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p3);
break; break;
} }
@@ -3855,7 +3880,7 @@ case OP_DropTable: {
** is dropped in order to keep the internal representation of the ** is dropped in order to keep the internal representation of the
** schema consistent with what is on disk. ** schema consistent with what is on disk.
*/ */
case OP_DropIndex: { case OP_DropIndex: { /* no stack growth */
sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p3); sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p3);
break; break;
} }
@@ -3867,7 +3892,7 @@ case OP_DropIndex: {
** is dropped in order to keep the internal representation of the ** is dropped in order to keep the internal representation of the
** schema consistent with what is on disk. ** schema consistent with what is on disk.
*/ */
case OP_DropTrigger: { case OP_DropTrigger: { /* no stack growth */
sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3); sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3);
break; break;
} }
@@ -3932,7 +3957,7 @@ case OP_IntegrityCk: {
** Write the integer on the top of the stack ** Write the integer on the top of the stack
** into the temporary storage list. ** into the temporary storage list.
*/ */
case OP_ListWrite: { case OP_ListWrite: { /* no stack growth */
Keylist *pKeylist; Keylist *pKeylist;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
pKeylist = p->pList; pKeylist = p->pList;
@@ -3956,7 +3981,7 @@ case OP_ListWrite: {
** **
** Rewind the temporary buffer back to the beginning. ** Rewind the temporary buffer back to the beginning.
*/ */
case OP_ListRewind: { case OP_ListRewind: { /* no stack growth */
/* What this opcode codes, really, is reverse the order of the /* What this opcode codes, really, is reverse the order of the
** linked list of Keylist structures so that they are read out ** linked list of Keylist structures so that they are read out
** in the same order that they were read in. */ ** in the same order that they were read in. */
@@ -4003,7 +4028,7 @@ case OP_ListRead: {
** **
** Reset the temporary storage buffer so that it holds nothing. ** Reset the temporary storage buffer so that it holds nothing.
*/ */
case OP_ListReset: { case OP_ListReset: { /* no stack growth */
if( p->pList ){ if( p->pList ){
sqlite3VdbeKeylistFree(p->pList); sqlite3VdbeKeylistFree(p->pList);
p->pList = 0; p->pList = 0;
@@ -4018,7 +4043,7 @@ case OP_ListReset: {
** AggContextPop opcode. ** AggContextPop opcode.
** **
*/ */
case OP_AggContextPush: { case OP_AggContextPush: { /* no stack growth */
p->pAgg++; p->pAgg++;
assert( p->pAgg<&p->apAgg[p->nAgg] ); assert( p->pAgg<&p->apAgg[p->nAgg] );
break; break;
@@ -4029,7 +4054,7 @@ case OP_AggContextPush: {
** Restore the aggregator to the state it was in when AggContextPush ** Restore the aggregator to the state it was in when AggContextPush
** was last called. Any data in the current aggregator is deleted. ** was last called. Any data in the current aggregator is deleted.
*/ */
case OP_AggContextPop: { case OP_AggContextPop: { /* no stack growth */
p->pAgg--; p->pAgg--;
assert( p->pAgg>=p->apAgg ); assert( p->pAgg>=p->apAgg );
break; break;
@@ -4043,7 +4068,7 @@ case OP_AggContextPop: {
** opcode. The context stores the last insert row id, the last statement change ** opcode. The context stores the last insert row id, the last statement change
** count, and the current statement change count. ** count, and the current statement change count.
*/ */
case OP_ContextPush: { case OP_ContextPush: { /* no stack growth */
int i = p->contextStackTop++; int i = p->contextStackTop++;
Context *pContext; Context *pContext;
@@ -4068,7 +4093,7 @@ case OP_ContextPush: {
** executed. The context stores the last insert row id, the last statement ** executed. The context stores the last insert row id, the last statement
** change count, and the current statement change count. ** change count, and the current statement change count.
*/ */
case OP_ContextPop: { case OP_ContextPop: { /* no stack growth */
Context *pContext = &p->contextStack[--p->contextStackTop]; Context *pContext = &p->contextStack[--p->contextStackTop];
assert( p->contextStackTop>=0 ); assert( p->contextStackTop>=0 );
db->lastRowid = pContext->lastRowid; db->lastRowid = pContext->lastRowid;
@@ -4085,7 +4110,7 @@ case OP_ContextPop: {
** and put them on the sorter. The key and data should have been ** and put them on the sorter. The key and data should have been
** made using the MakeRecord opcode. ** made using the MakeRecord opcode.
*/ */
case OP_SortPut: { case OP_SortPut: { /* no stack growth */
Mem *pNos = &pTos[-1]; Mem *pNos = &pTos[-1];
Sorter *pSorter; Sorter *pSorter;
assert( pNos>=p->aStack ); assert( pNos>=p->aStack );
@@ -4109,7 +4134,7 @@ case OP_SortPut: {
** mergesort. The P3 argument is a pointer to a KeyInfo structure ** mergesort. The P3 argument is a pointer to a KeyInfo structure
** that describes the keys to be sorted. ** that describes the keys to be sorted.
*/ */
case OP_Sort: { case OP_Sort: { /* no stack growth */
int i; int i;
KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3; KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
Sorter *pElem; Sorter *pElem;
@@ -4171,7 +4196,7 @@ case OP_SortNext: {
** **
** Remove any elements that remain on the sorter. ** Remove any elements that remain on the sorter.
*/ */
case OP_SortReset: { case OP_SortReset: { /* no stack growth */
sqlite3VdbeSorterReset(p); sqlite3VdbeSorterReset(p);
break; break;
} }
@@ -4186,7 +4211,7 @@ case OP_SortReset: {
** stack is popped once if P2 is 1. If P2 is zero, then ** stack is popped once if P2 is 1. If P2 is zero, then
** the original data remains on the stack. ** the original data remains on the stack.
*/ */
case OP_MemStore: { case OP_MemStore: { /* no stack growth */
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
assert( pOp->p1>=0 && pOp->p1<p->nMem ); assert( pOp->p1>=0 && pOp->p1<p->nMem );
rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos); rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos);
@@ -4225,7 +4250,7 @@ case OP_MemLoad: {
** This instruction throws an error if the memory cell is not initially ** This instruction throws an error if the memory cell is not initially
** an integer. ** an integer.
*/ */
case OP_MemMax: { case OP_MemMax: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Mem *pMem; Mem *pMem;
assert( pTos>=p->aStack ); assert( pTos>=p->aStack );
@@ -4249,7 +4274,7 @@ case OP_MemMax: {
** This instruction throws an error if the memory cell is not initially ** This instruction throws an error if the memory cell is not initially
** an integer. ** an integer.
*/ */
case OP_MemIncr: { case OP_MemIncr: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Mem *pMem; Mem *pMem;
assert( i>=0 && i<p->nMem ); assert( i>=0 && i<p->nMem );
@@ -4267,7 +4292,7 @@ case OP_MemIncr: {
** If the value of memory cell P1 is 1 or greater, jump to P2. This ** If the value of memory cell P1 is 1 or greater, jump to P2. This
** opcode assumes that memory cell P1 holds an integer value. ** opcode assumes that memory cell P1 holds an integer value.
*/ */
case OP_IfMemPos: { case OP_IfMemPos: { /* no stack growth */
int i = pOp->p1; int i = pOp->p1;
Mem *pMem; Mem *pMem;
assert( i>=0 && i<p->nMem ); assert( i>=0 && i<p->nMem );
@@ -4289,7 +4314,7 @@ case OP_IfMemPos: {
** there is no GROUP BY expression). In this case it is illegal to invoke ** there is no GROUP BY expression). In this case it is illegal to invoke
** OP_AggFocus. ** OP_AggFocus.
*/ */
case OP_AggReset: { case OP_AggReset: { /* no stack growth */
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO ); assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
if( pOp->p1 ){ if( pOp->p1 ){
rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3); rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
@@ -4313,7 +4338,7 @@ case OP_AggReset: {
** The aggregate will operate out of aggregate column P2. ** The aggregate will operate out of aggregate column P2.
** P3 is a pointer to the FuncDef structure for the function. ** P3 is a pointer to the FuncDef structure for the function.
*/ */
case OP_AggInit: { case OP_AggInit: { /* no stack growth */
int i = pOp->p2; int i = pOp->p2;
assert( i>=0 && i<p->pAgg->nMem ); assert( i>=0 && i<p->pAgg->nMem );
p->pAgg->apFunc[i] = (FuncDef*)pOp->p3; p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
@@ -4331,7 +4356,7 @@ case OP_AggInit: {
** Ideally, this index would be another parameter, but there are ** Ideally, this index would be another parameter, but there are
** no free parameters left. The integer is popped from the stack. ** no free parameters left. The integer is popped from the stack.
*/ */
case OP_AggFunc: { case OP_AggFunc: { /* no stack growth */
int n = pOp->p2; int n = pOp->p2;
int i; int i;
Mem *pMem, *pRec; Mem *pMem, *pRec;
@@ -4389,7 +4414,7 @@ case OP_AggFunc: {
** zero or more AggNext operations. You must not execute an AggFocus ** zero or more AggNext operations. You must not execute an AggFocus
** in between an AggNext and an AggReset. ** in between an AggNext and an AggReset.
*/ */
case OP_AggFocus: { case OP_AggFocus: { /* no stack growth */
char *zKey; char *zKey;
int nKey; int nKey;
int res; int res;
@@ -4423,7 +4448,7 @@ case OP_AggFocus: {
** Move the top of the stack into the P2-th field of the current ** Move the top of the stack into the P2-th field of the current
** aggregate. String values are duplicated into new memory. ** aggregate. String values are duplicated into new memory.
*/ */
case OP_AggSet: { case OP_AggSet: { /* no stack growth */
AggElem *pFocus; AggElem *pFocus;
int i = pOp->p2; int i = pOp->p2;
pFocus = p->pAgg->pCurrent; pFocus = p->pAgg->pCurrent;
@@ -4488,7 +4513,7 @@ case OP_AggGet: {
** zero or more AggNext operations. You must not execute an AggFocus ** zero or more AggNext operations. You must not execute an AggFocus
** in between an AggNext and an AggReset. ** in between an AggNext and an AggReset.
*/ */
case OP_AggNext: { case OP_AggNext: { /* no stack growth */
int res; int res;
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
CHECK_FOR_INTERRUPT; CHECK_FOR_INTERRUPT;
@@ -4549,7 +4574,7 @@ case OP_AggNext: {
** machines to be created and run. It may not be called from within ** machines to be created and run. It may not be called from within
** a transaction. ** a transaction.
*/ */
case OP_Vacuum: { case OP_Vacuum: { /* no stack growth */
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = sqlite3RunVacuum(&p->zErrMsg, db); rc = sqlite3RunVacuum(&p->zErrMsg, db);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
@@ -4565,7 +4590,7 @@ case OP_Vacuum: {
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
** then only the currently executing statement is affected. ** then only the currently executing statement is affected.
*/ */
case OP_Expire: { case OP_Expire: { /* no stack growth */
if( !pOp->p1 ){ if( !pOp->p1 ){
sqlite3ExpirePreparedStatements(db); sqlite3ExpirePreparedStatements(db);
}else{ }else{
@@ -4592,6 +4617,9 @@ default: {
*****************************************************************************/ *****************************************************************************/
} }
/* Make sure the stack limit was not exceeded */
assert( pTos<=pStackLimit );
#ifdef VDBE_PROFILE #ifdef VDBE_PROFILE
{ {
long long elapse = hwtime() - start; long long elapse = hwtime() - start;

View File

@@ -406,6 +406,7 @@ int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemRelease(Mem *p);
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8); void sqlite3VdbeMemSanity(Mem*, u8);
int sqlite3VdbeOpcodeUsesStack(u8);
#endif #endif
int sqlite3VdbeMemTranslate(Mem*, u8); int sqlite3VdbeMemTranslate(Mem*, u8);
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf); void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);

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. ** Loop through the program looking for P2 values that are negative.
** Each such value is a label. Resolve the label by setting the P2 ** 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 ** 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 ** to an OP_Function or P2 to an OP_AggFunc opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. ** 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 i;
int nMax = 0; int nMaxArgs = 0;
int nMaxStack = p->nOp;
Op *pOp; Op *pOp;
int *aLabel = p->aLabel; int *aLabel = p->aLabel;
if( aLabel==0 ) return;
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode; u8 opcode = pOp->opcode;
/* Todo: Maybe OP_AggFunc should change to use P1 in the same /* 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( opcode==OP_Function ){
if( pOp->p1>nMax ) nMax = pOp->p1; if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;
}else if( opcode==OP_AggFunc ){ }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; if( pOp->p2>=0 ) continue;
@@ -200,7 +249,9 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
} }
sqliteFree(p->aLabel); sqliteFree(p->aLabel);
p->aLabel = 0; p->aLabel = 0;
*pMaxFuncArgs = nMax;
*pMaxFuncArgs = nMaxArgs;
*pMaxStack = nMaxStack;
} }
/* /*
@@ -641,12 +692,14 @@ void sqlite3VdbeMakeReady(
*/ */
if( p->aStack==0 ){ if( p->aStack==0 ){
int nArg; /* Maximum number of args passed to a user function. */ 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); resizeOpArray(p, p->nOp);
assert( nVar>=0 ); assert( nVar>=0 );
n = isExplain ? 10 : p->nOp; assert( nStack<p->nOp );
nStack = isExplain ? 10 : nStack;
p->aStack = sqliteMalloc( p->aStack = sqliteMalloc(
n*sizeof(p->aStack[0]) /* aStack */ nStack*sizeof(p->aStack[0]) /* aStack */
+ nArg*sizeof(Mem*) /* apArg */ + nArg*sizeof(Mem*) /* apArg */
+ nVar*sizeof(Mem) /* aVar */ + nVar*sizeof(Mem) /* aVar */
+ nVar*sizeof(char*) /* azVar */ + nVar*sizeof(char*) /* azVar */
@@ -655,7 +708,7 @@ void sqlite3VdbeMakeReady(
+ nAgg*sizeof(Agg) /* Aggregate contexts */ + nAgg*sizeof(Agg) /* Aggregate contexts */
); );
if( !sqlite3_malloc_failed ){ if( !sqlite3_malloc_failed ){
p->aMem = &p->aStack[n]; p->aMem = &p->aStack[nStack];
p->nMem = nMem; p->nMem = nMem;
p->aVar = &p->aMem[nMem]; p->aVar = &p->aMem[nMem];
p->nVar = nVar; p->nVar = nVar;

View File

@@ -10,7 +10,7 @@
#*********************************************************************** #***********************************************************************
# This file runs all tests. # This file runs all tests.
# #
# $Id: quick.test,v 1.35 2005/03/29 03:11:00 danielk1977 Exp $ # $Id: quick.test,v 1.36 2005/03/29 08:26:13 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -19,7 +19,6 @@ proc finish_test {} {}
set ISQUICK 1 set ISQUICK 1
set EXCLUDE { set EXCLUDE {
alter.test
all.test all.test
btree2.test btree2.test
btree3.test btree3.test

View File

@@ -34,14 +34,46 @@ Example:
$ ./testfixture ../sqlite/test/select1.test 2> memtrace.out $ ./testfixture ../sqlite/test/select1.test 2> memtrace.out
$ tclsh $argv0 ?-r <malloc-number>? ./testfixture memtrace.out $ tclsh $argv0 ?-r <malloc-number>? ./testfixture memtrace.out
" "
if { [llength $argv]!=2 && [llength $argv]!=4 } {
set prg [file tail $argv0]
proc usage {} {
set prg [file tail $::argv0]
puts "Usage: $prg ?-r <malloc-number>? <binary file> <mem trace file>" puts "Usage: $prg ?-r <malloc-number>? <binary file> <mem trace file>"
puts "" puts ""
puts [string trim $doco] puts [string trim $::doco]
exit -1 exit -1
} }
proc shift {listvar} {
upvar $listvar l
set ret [lindex $l 0]
set l [lrange $l 1 end]
return $ret
}
# Argument handling. The following vars are set:
#
# $exe - the name of the executable (i.e. "testfixture" or "./sqlite3")
# $memfile - the name of the file containing the trace output.
# $report_at - The malloc number to stop and report at. Or -1 to read
# all of $memfile.
#
set report_at -1
while {[llength $argv]>2} {
set arg [shift argv]
switch -- $arg {
"-r" {
set report_at [shift argv]
}
default {
usage
}
}
}
if {[llength $argv]!=2} usage
set exe [lindex $argv 0]
set memfile [lindex $argv 1]
# If stack traces are enabled, the 'addr2line' program is called to # If stack traces are enabled, the 'addr2line' program is called to
# translate a binary stack address into a human-readable form. # translate a binary stack address into a human-readable form.
set addr2line addr2line set addr2line addr2line
@@ -69,17 +101,6 @@ set iPeak 0 ;# nMalloc when nPeak was set.
# #
array unset memmap array unset memmap
# The executable program being analyzed.
if {[llength $argv]==2} {
set exe [lindex $argv 0]
set memfile [lindex $argv 1]
set report_at -1
} else {
set exe [lindex $argv 2]
set memfile [lindex $argv 3]
set report_at [lindex $argv 1]
}
proc process_input {input_file array_name} { proc process_input {input_file array_name} {
upvar $array_name mem upvar $array_name mem
set input [open $input_file] set input [open $input_file]