]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Rework internal data structures to make the VDBE about 15% smaller. (CVS 1203)
authordrh <drh@noemail.net>
Sat, 31 Jan 2004 19:22:56 +0000 (19:22 +0000)
committerdrh <drh@noemail.net>
Sat, 31 Jan 2004 19:22:56 +0000 (19:22 +0000)
FossilOrigin-Name: 8273c74bd09d1a044cb5154498b0a39939f6e3ed

manifest
manifest.uuid
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
tool/memleak.awk

index a0d0ce4cf1d14a6094bc6265f412263132684f42..d7418dfe8fd4c76271f6110f98fba14989ed08b6 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Rework\sthe\sVDBE\sdata\sstructures\sto\scombine\sstring\srepresentations\sinto\sthe\nsame\sstructure\swith\sinteger\sand\sfloating\spoint.\s\sThis\sopens\sthe\sdoor\sto\nsignificant\soptimizations.\s(CVS\s1202)
-D 2004-01-30T14:49:17
+C Rework\sinternal\sdata\sstructures\sto\smake\sthe\sVDBE\sabout\s15%\ssmaller.\s(CVS\s1203)
+D 2004-01-31T19:22:56
 F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -61,10 +61,10 @@ F src/trigger.c ce83e017b407d046e909d05373d7f8ee70f9f7f9
 F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397
 F src/util.c 64995b5949a5d377629ffd2598747bc771cade1e
 F src/vacuum.c 77485a64a6e4e358170f150fff681c1624a092b0
-F src/vdbe.c fcd5b6f27b3041ef022cf04ecaf63bbdccf88950
+F src/vdbe.c 36a93b5e213100b4c25ca614e69b74a5056154d6
 F src/vdbe.h 3957844e46fea71fd030e78f6a3bd2f7e320fb43
-F src/vdbeInt.h 6f12f5b9344cbb0e5cc2277458d84f7b951122bf
-F src/vdbeaux.c 358d955a23d29e268a3b45c428e49292b89dfcf5
+F src/vdbeInt.h 8a3baf749115cba81a810b7a52208aef055eda7b
+F src/vdbeaux.c c55d87d6658487e87ef09ca80c1aa2f314024fed
 F src/where.c 1302d728bd338c237e6a8282e4e3eadbbdf11e45
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test c26848402e7ac829e043e1fa5e0eb87032e5d81d
@@ -147,7 +147,7 @@ F test/where.test cb3a2ed062ce4b5f08aff2d08027c6a46d68c47b
 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
 F tool/lemon.c e37dcb5b8cdb16f4ac98338134bf8d8cd28e399f
 F tool/lempar.c 0b5e7a58634e0d448929b8e85f7981c2aa708d57
-F tool/memleak.awk 16ef9493dcd36146f806e75148f4bb0201a123ec
+F tool/memleak.awk b744b6109566206c746d826f6ecdba34662216bc
 F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8
 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
@@ -182,7 +182,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P af73fbca839f8cbe39c21f1f9e439fe9b79005c8
-R 498fe1480c9c56c03607a7a6c9f9b96c
+P c0faa1c67a967f028cd018e58988fb08bc814d3d
+R ee0cff331d148b843c9a28e532dc12e0
 U drh
-Z 222ac74ccb7f92ccb269c2c94a8bca52
+Z 9c3d28234884b5bb6cce05f45417ae61
index c18d5a8d3cb42d8bbc7a8929e549e2a993916258..4f458f6a65b851dc3f80b32aa971026d051599cd 100644 (file)
@@ -1 +1 @@
-c0faa1c67a967f028cd018e58988fb08bc814d3d
\ No newline at end of file
+8273c74bd09d1a044cb5154498b0a39939f6e3ed
\ No newline at end of file
index 86499f90806a4f5133014ff1933ab067469e94b6..5bac6745e72cf125d87cd2fbbd7abeda506aa0b4 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.252 2004/01/30 14:49:17 drh Exp $
+** $Id: vdbe.c,v 1.253 2004/01/31 19:22:56 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -182,9 +182,8 @@ static AggElem *_AggInFocus(Agg *p){
 ** Convert the given stack entity into a string if it isn't one
 ** already.
 */
-#define Stringify(P,I) if((aStack[I].flags & MEM_Str)==0){hardStringify(P,I);}
-static int hardStringify(Vdbe *p, int i){
-  Mem *pStack = &p->aStack[i];
+#define Stringify(P) if(((P)->flags & MEM_Str)==0){hardStringify(P);}
+static int hardStringify(Mem *pStack){
   int fg = pStack->flags;
   if( fg & MEM_Real ){
     sqlite_snprintf(sizeof(pStack->zShort),pStack->zShort,"%.15g",pStack->r);
@@ -193,9 +192,9 @@ static int hardStringify(Vdbe *p, int i){
   }else{
     pStack->zShort[0] = 0;
   }
-  p->aStack[i].z = pStack->zShort;
+  pStack->z = pStack->zShort;
   pStack->n = strlen(pStack->zShort)+1;
-  pStack->flags = MEM_Str;
+  pStack->flags = MEM_Str | MEM_Short;
   return 0;
 }
 
@@ -206,19 +205,18 @@ static int hardStringify(Vdbe *p, int i){
 ** will fit but this routine always mallocs for space.
 ** Return non-zero if we run out of memory.
 */
-#define Dynamicify(P,I) ((aStack[I].flags & MEM_Dyn)==0 ? hardDynamicify(P,I):0)
-static int hardDynamicify(Vdbe *p, int i){
-  Mem *pStack = &p->aStack[i];
+#define Dynamicify(P) (((P)->flags & MEM_Dyn)==0 ? hardDynamicify(P):0)
+static int hardDynamicify(Mem *pStack){
   int fg = pStack->flags;
   char *z;
   if( (fg & MEM_Str)==0 ){
-    hardStringify(p, i);
+    hardStringify(pStack);
   }
   assert( (fg & MEM_Dyn)==0 );
   z = sqliteMallocRaw( pStack->n );
   if( z==0 ) return 1;
-  memcpy(z, p->aStack[i].z, pStack->n);
-  p->aStack[i].z = z;
+  memcpy(z, pStack->z, pStack->n);
+  pStack->z = z;
   pStack->flags |= MEM_Dyn;
   return 0;
 }
@@ -234,10 +232,9 @@ static int hardDynamicify(Vdbe *p, int i){
 ** string that the stack entry itself controls.  In other words, it
 ** converts an MEM_Ephem string into an MEM_Dyn string.
 */
-#define Deephemeralize(P,I) \
-   if( ((P)->aStack[I].flags&MEM_Ephem)!=0 && hardDeephem(P,I) ){ goto no_mem;}
-static int hardDeephem(Vdbe *p, int i){
-  Mem *pStack = &p->aStack[i];
+#define Deephemeralize(P) \
+   if( ((P)->flags&MEM_Ephem)!=0 && hardDeephem(P) ){ goto no_mem;}
+static int hardDeephem(Mem *pStack){
   char *z;
   assert( (pStack->flags & MEM_Ephem)!=0 );
   z = sqliteMallocRaw( pStack->n );
@@ -250,13 +247,22 @@ static int hardDeephem(Vdbe *p, int i){
 }
 
 /*
-** Release the memory associated with the given stack level
+** Release the memory associated with the given stack level.  This
+** leaves the Mem.flags field in an inconsistent state.
+*/
+#define Release(P) if((P)->flags&MEM_Dyn){ sqliteFree((P)->z); }
+
+/*
+** Pop the stack N times.
 */
-#define Release(P,I)  if((P)->aStack[I].flags&MEM_Dyn){ hardRelease(P,I); }
-static void hardRelease(Vdbe *p, int i){
-  sqliteFree(p->aStack[i].z);
-  p->aStack[i].z = 0;
-  p->aStack[i].flags &= ~(MEM_Str|MEM_Dyn|MEM_Static|MEM_Ephem);
+static void popStack(Mem **ppTos, int N){
+  Mem *pTos = *ppTos;
+  while( N>0 ){
+    N--;
+    Release(pTos);
+    pTos--;
+  }
+  *ppTos = pTos;
 }
 
 /*
@@ -295,19 +301,18 @@ static int toInt(const char *zNum, int *pNum){
 ** Any prior string or real representation is invalidated.  
 ** NULLs are converted into 0.
 */
-#define Integerify(P,I) \
-    if(((P)->aStack[(I)].flags&MEM_Int)==0){ hardIntegerify(P,I); }
-static void hardIntegerify(Vdbe *p, int i){
-  if( p->aStack[i].flags & MEM_Real ){
-    p->aStack[i].i = (int)p->aStack[i].r;
-    Release(p, i);
-  }else if( p->aStack[i].flags & MEM_Str ){
-    toInt(p->aStack[i].z, &p->aStack[i].i);
-    Release(p, i);
+#define Integerify(P) if(((P)->flags&MEM_Int)==0){ hardIntegerify(P); }
+static void hardIntegerify(Mem *pStack){
+  if( pStack->flags & MEM_Real ){
+    pStack->i = (int)pStack->r;
+    Release(pStack);
+  }else if( pStack->flags & MEM_Str ){
+    toInt(pStack->z, &pStack->i);
+    Release(pStack);
   }else{
-    p->aStack[i].i = 0;
+    pStack->i = 0;
   }
-  p->aStack[i].flags = MEM_Int;
+  pStack->flags = MEM_Int;
 }
 
 /*
@@ -316,17 +321,16 @@ static void hardIntegerify(Vdbe *p, int i){
 ** Any prior string or integer representation is retained.
 ** NULLs are converted into 0.0.
 */
-#define Realify(P,I) \
-    if(((P)->aStack[(I)].flags&MEM_Real)==0){ hardRealify(P,I); }
-static void hardRealify(Vdbe *p, int i){
-  if( p->aStack[i].flags & MEM_Str ){
-    p->aStack[i].r = sqliteAtoF(p->aStack[i].z);
-  }else if( p->aStack[i].flags & MEM_Int ){
-    p->aStack[i].r = p->aStack[i].i;
+#define Realify(P) if(((P)->flags&MEM_Real)==0){ hardRealify(P); }
+static void hardRealify(Mem *pStack){
+  if( pStack->flags & MEM_Str ){
+    pStack->r = sqliteAtoF(pStack->z);
+  }else if( pStack->flags & MEM_Int ){
+    pStack->r = pStack->i;
   }else{
-    p->aStack[i].r = 0.0;
+    pStack->r = 0.0;
   }
-  p->aStack[i].flags |= MEM_Real;
+  pStack->flags |= MEM_Real;
 }
 
 /*
@@ -361,17 +365,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
   return sHead.pNext;
 }
 
-/*
-** Code contained within the VERIFY() macro is not needed for correct
-** execution.  It is there only to catch errors.  So when we compile
-** with NDEBUG=1, the VERIFY() code is omitted.
-*/
-#ifdef NDEBUG
-# define VERIFY(X)
-#else
-# define VERIFY(X) X
-#endif
-
 /*
 ** The following routine works like a replacement for the standard
 ** library routine fgets().  The difference is in how end-of-line (EOL)
@@ -485,7 +478,7 @@ int sqliteVdbeExec(
   Op *pOp;                   /* Current operation */
   int rc = SQLITE_OK;        /* Value to return */
   sqlite *db = p->db;        /* The database */
-  Mem *aStack = p->aStack;   /* The operand stack */
+  Mem *pTos;                 /* Top entry in the operand stack */
   char zBuf[100];            /* Space to sprintf() an integer */
 #ifdef VDBE_PROFILE
   unsigned long long start;  /* CPU clock count at start of opcode */
@@ -501,13 +494,14 @@ int sqliteVdbeExec(
   p->rc = SQLITE_OK;
   assert( p->explain==0 );
   if( sqlite_malloc_failed ) goto no_mem;
+  pTos = p->pTos;
   if( p->popStack ){
-    sqliteVdbePopStack(p, p->popStack);
+    popStack(&pTos, p->popStack);
     p->popStack = 0;
   }
   for(pc=p->pc; rc==SQLITE_OK; pc++){
     assert( pc>=0 && pc<p->nOp );
-    assert( p->tos<=pc );
+    assert( pTos<=&p->aStack[pc] );
 #ifdef VDBE_PROFILE
     origPc = pc;
     start = hwtime();
@@ -639,6 +633,7 @@ case OP_Return: {
 */
 case OP_Halt: {
   p->magic = VDBE_MAGIC_HALT;
+  p->pTos = pTos;
   if( pOp->p1!=SQLITE_OK ){
     p->rc = pOp->p1;
     p->errorAction = pOp->p2;
@@ -658,13 +653,13 @@ case OP_Halt: {
 ** then it is assumed to be a string representation of the same integer.
 */
 case OP_Integer: {
-  int i = ++p->tos;
-  aStack[i].i = pOp->p1;
-  aStack[i].flags = MEM_Int;
+  pTos++;
+  pTos->i = pOp->p1;
+  pTos->flags = MEM_Int;
   if( pOp->p3 ){
-    aStack[i].z = pOp->p3;
-    aStack[i].flags |= MEM_Str | MEM_Static;
-    aStack[i].n = strlen(pOp->p3)+1;
+    pTos->z = pOp->p3;
+    pTos->flags |= MEM_Str | MEM_Static;
+    pTos->n = strlen(pOp->p3)+1;
   }
   break;
 }
@@ -675,17 +670,14 @@ case OP_Integer: {
 ** NULL is pushed onto the stack.
 */
 case OP_String: {
-  int i = ++p->tos;
-  char *z;
-  z = pOp->p3;
+  char *z = pOp->p3;
+  pTos++;
   if( z==0 ){
-    aStack[i].z = 0;
-    aStack[i].n = 0;
-    aStack[i].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }else{
-    aStack[i].z = z;
-    aStack[i].n = strlen(z) + 1;
-    aStack[i].flags = MEM_Str | MEM_Static;
+    pTos->z = z;
+    pTos->n = strlen(z) + 1;
+    pTos->flags = MEM_Str | MEM_Static;
   }
   break;
 }
@@ -700,16 +692,14 @@ case OP_String: {
 ** sqlite_bind() API.
 */
 case OP_Variable: {
-  int i = ++p->tos;
   int j = pOp->p1 - 1;
+  pTos++;
   if( j>=0 && j<p->nVar && p->azVar[j]!=0 ){
-    aStack[i].z = p->azVar[j];
-    aStack[i].n = p->anVar[j];
-    aStack[i].flags = MEM_Str | MEM_Static;
+    pTos->z = p->azVar[j];
+    pTos->n = p->anVar[j];
+    pTos->flags = MEM_Str | MEM_Static;
   }else{
-    aStack[i].z = 0;
-    aStack[i].n = 0;
-    aStack[i].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }
   break;
 }
@@ -719,8 +709,9 @@ case OP_Variable: {
 ** P1 elements are popped off of the top of stack and discarded.
 */
 case OP_Pop: {
-  assert( p->tos+1>=pOp->p1 );
-  sqliteVdbePopStack(p, pOp->p1);
+  assert( pOp->p1>=0 );
+  popStack(&pTos, pOp->p1);
+  assert( pTos>=&p->aStack[-1] );
   break;
 }
 
@@ -740,26 +731,23 @@ case OP_Pop: {
 ** Also see the Pull instruction.
 */
 case OP_Dup: {
-  int i = p->tos - pOp->p1;
-  int j = ++p->tos;
-  VERIFY( if( i<0 ) goto not_enough_stack; )
-  memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS);
-  if( aStack[j].flags & MEM_Str ){
-    int isStatic = (aStack[j].flags & MEM_Static)!=0;
-    if( pOp->p2 || isStatic ){
-      aStack[j].z = aStack[i].z;
-      aStack[j].flags &= ~MEM_Dyn;
-      if( !isStatic ) aStack[j].flags |= MEM_Ephem;
-    }else if( aStack[i].n<=NBFS ){
-      memcpy(aStack[j].zShort, aStack[i].z, aStack[j].n);
-      aStack[j].z = aStack[j].zShort;
-      aStack[j].flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
-    }else{
-      aStack[j].z = sqliteMallocRaw( aStack[j].n );
-      if( aStack[j].z==0 ) goto no_mem;
-      memcpy(aStack[j].z, aStack[i].z, aStack[j].n);
-      aStack[j].flags &= ~(MEM_Static|MEM_Ephem);
-      aStack[j].flags |= MEM_Dyn;
+  Mem *pFrom = &pTos[-pOp->p1];
+  assert( pFrom<=pTos && pFrom>=p->aStack );
+  pTos++;
+  memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS);
+  if( pTos->flags & MEM_Str ){
+    if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){
+      pTos->flags &= ~MEM_Dyn;
+      pTos->flags |= MEM_Ephem;
+    }else if( pTos->flags & MEM_Short ){
+      memcpy(pTos->zShort, pFrom->zShort, pTos->n);
+      pTos->z = pTos->zShort;
+    }else if( (pTos->flags & MEM_Static)==0 ){
+      pTos->z = sqliteMallocRaw(pFrom->n);
+      if( sqlite_malloc_failed ) goto no_mem;
+      memcpy(pTos->z, pFrom->z, pFrom->n);
+      pTos->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short);
+      pTos->flags |= MEM_Dyn;
     }
   }
   break;
@@ -776,28 +764,31 @@ case OP_Dup: {
 ** See also the Dup instruction.
 */
 case OP_Pull: {
-  int from = p->tos - pOp->p1;
-  int to = p->tos;
+  Mem *pFrom = &pTos[-pOp->p1];
   int i;
   Mem ts;
-  VERIFY( if( from<0 ) goto not_enough_stack; )
-  Deephemeralize(p, from);
-  ts = aStack[from];
-  Deephemeralize(p, to);
-  for(i=from; i<to; i++){
-    Deephemeralize(p, i+1);
-    aStack[i] = aStack[i+1];
-    assert( (aStack[i].flags & MEM_Ephem)==0 );
-    if( aStack[i].flags & (MEM_Dyn|MEM_Static) ){
-      aStack[i].z = aStack[i+1].z;
-    }else{
-      aStack[i].z = aStack[i].zShort;
+
+  /* Deephemeralize(pFrom); *** not needed */
+  ts = *pFrom;
+  Deephemeralize(pTos);
+  for(i=0; i<pOp->p1; i++, pFrom++){
+    Deephemeralize(&pFrom[1]);
+    *pFrom = pFrom[1];
+    assert( (pFrom->flags & MEM_Ephem)==0 );
+    if( pFrom->flags & MEM_Short ){
+      assert( pFrom->flags & MEM_Str );
+      assert( pFrom->z==pFrom[1].zShort );
+      assert( (pTos->flags & (MEM_Dyn|MEM_Static|MEM_Ephem))==0 );
+      pFrom->z = pFrom->zShort;
     }
   }
-  aStack[to] = ts;
-  assert( (aStack[to].flags & MEM_Ephem)==0 );
-  if( (aStack[to].flags & (MEM_Dyn|MEM_Static))==0 ){
-    aStack[to].z = aStack[to].zShort;
+  *pTos = ts;
+  /* assert( (pTos->flags & MEM_Ephem)==0 ); *** not needed */
+  if( pTos->flags & MEM_Short ){
+    assert( pTos->flags & MEM_Str );
+    assert( pTos->z==pTos[-pOp->p1].zShort );
+    assert( (pTos->flags & (MEM_Dyn|MEM_Static|MEM_Ephem))==0 );
+    pTos->z = pTos->zShort;
   }
   break;
 }
@@ -809,25 +800,21 @@ case OP_Pull: {
 ** of the top of the stack.  Then pop the top of the stack.
 */
 case OP_Push: {
-  int from = p->tos;
-  int to = p->tos - pOp->p1;
+  Mem *pTo = &pTos[-pOp->p1];
 
-  VERIFY( if( to<0 ) goto not_enough_stack; )
-  if( aStack[to].flags & MEM_Dyn ){
-    sqliteFree(aStack[to].z);
-  }
-  Deephemeralize(p, from);
-  aStack[to] = aStack[from];
-  if( aStack[to].flags & (MEM_Dyn|MEM_Static|MEM_Ephem) ){
-    aStack[to].z = aStack[from].z;
-  }else{
-    aStack[to].z = aStack[to].zShort;
+  assert( pTo>=p->aStack );
+  Deephemeralize(pTos);
+  Release(pTo);
+  *pTo = *pTos;
+  if( pTo->flags & MEM_Short ){
+    assert( pTo->z==pTos->zShort );
+    pTo->z = pTo->zShort;
   }
-  aStack[from].flags = 0;
-  p->tos--;
+  pTos--;
   break;
 }
 
+
 /* Opcode: ColumnName P1 * P3
 **
 ** P3 becomes the P1-th column name (first is 0).  An array of pointers
@@ -847,32 +834,37 @@ case OP_ColumnName: {
 ** 3rd parameter.
 */
 case OP_Callback: {
-  int i = p->tos - pOp->p1 + 1;
-  int j;
-  VERIFY( if( i<0 ) goto not_enough_stack; )
-  for(j=i; j<=p->tos; j++){
-    if( aStack[j].flags & MEM_Null ){
-      aStack[j].z = 0;
+  int i;
+  char **azArgv = p->zArgv;
+  Mem *pCol;
+
+  pCol = &pTos[1-pOp->p1];
+  assert( pCol>=p->aStack );
+  for(i=0; i<pOp->p1; i++, pCol++){
+    if( pCol->flags & MEM_Null ){
+      azArgv[i] = 0;
     }else{
-      Stringify(p, j);
+      Stringify(pCol);
+      azArgv[i] = pCol->z;
     }
-    p->zArgv[j] = aStack[j].z;
   }
-  p->zArgv[p->tos+1] = 0;
+  azArgv[i] = 0;
   if( p->xCallback==0 ){
-    p->azResColumn = &p->zArgv[i];
+    p->azResColumn = azArgv;
     p->nResColumn = pOp->p1;
     p->popStack = pOp->p1;
     p->pc = pc + 1;
+    p->pTos = pTos;
     return SQLITE_ROW;
   }
   if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
-  if( p->xCallback(p->pCbArg, pOp->p1, &p->zArgv[i], p->azColName)!=0 ){
+  if( p->xCallback(p->pCbArg, pOp->p1, azArgv, p->azColName)!=0 ){
     rc = SQLITE_ABORT;
   }
   if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
   p->nCallback++;
-  sqliteVdbePopStack(p, pOp->p1);
+  popStack(&pTos, pOp->p1);
+  assert( pTos>=&p->aStack[-1] );
   if( sqlite_malloc_failed ) goto no_mem;
   break;
 }
@@ -926,48 +918,53 @@ case OP_Concat: {
   int i, j;
   char *zSep;
   int nSep;
+  Mem *pTerm;
 
   nField = pOp->p1;
   zSep = pOp->p3;
   if( zSep==0 ) zSep = "";
   nSep = strlen(zSep);
-  VERIFY( if( p->tos+1<nField ) goto not_enough_stack; )
+  assert( &pTos[1-nField] >= p->aStack );
   nByte = 1 - nSep;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( aStack[i].flags & MEM_Null ){
+  pTerm = &pTos[1-nField];
+  for(i=0; i<nField; i++, pTerm++){
+    if( pTerm->flags & MEM_Null ){
       nByte = -1;
       break;
     }else{
-      Stringify(p, i);
-      nByte += aStack[i].n - 1 + nSep;
+      Stringify(pTerm);
+      nByte += pTerm->n - 1 + nSep;
     }
   }
   if( nByte<0 ){
-    if( pOp->p2==0 ) sqliteVdbePopStack(p, nField);
-    p->tos++;
-    aStack[p->tos].flags = MEM_Null;
-    aStack[p->tos].z = 0;
+    if( pOp->p2==0 ){
+      popStack(&pTos, nField);
+    }
+    pTos++;
+    pTos->flags = MEM_Null;
     break;
   }
   zNew = sqliteMallocRaw( nByte );
   if( zNew==0 ) goto no_mem;
   j = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( (aStack[i].flags & MEM_Null)==0 ){
-      memcpy(&zNew[j], aStack[i].z, aStack[i].n-1);
-      j += aStack[i].n-1;
-    }
-    if( nSep>0 && i<p->tos ){
+  pTerm = &pTos[1-nField];
+  for(i=j=0; i<nField; i++, pTerm++){
+    assert( pTerm->flags & MEM_Str );
+    memcpy(&zNew[j], pTerm->z, pTerm->n-1);
+    j += pTerm->n-1;
+    if( nSep>0 && i<nField-1 ){
       memcpy(&zNew[j], zSep, nSep);
       j += nSep;
     }
   }
   zNew[j] = 0;
-  if( pOp->p2==0 ) sqliteVdbePopStack(p, nField);
-  p->tos++;
-  aStack[p->tos].n = nByte;
-  aStack[p->tos].flags = MEM_Str|MEM_Dyn;
-  aStack[p->tos].z = zNew;
+  if( pOp->p2==0 ){
+    popStack(&pTos, nField);
+  }
+  pTos++;
+  pTos->n = nByte;
+  pTos->flags = MEM_Str|MEM_Dyn;
+  pTos->z = zNew;
   break;
 }
 
@@ -1022,17 +1019,17 @@ case OP_Subtract:
 case OP_Multiply:
 case OP_Divide:
 case OP_Remainder: {
-  int tos = p->tos;
-  int nos = tos - 1;
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  if( ((aStack[tos].flags | aStack[nos].flags) & MEM_Null)!=0 ){
-    POPSTACK;
-    Release(p, nos);
-    aStack[nos].flags = MEM_Null;
-  }else if( (aStack[tos].flags & aStack[nos].flags & MEM_Int)==MEM_Int ){
+  Mem *pNos = &pTos[-1];
+  assert( pNos>=p->aStack );
+  if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
+    Release(pTos);
+    pTos--;
+    Release(pTos);
+    pTos->flags = MEM_Null;
+  }else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){
     int a, b;
-    a = aStack[tos].i;
-    b = aStack[nos].i;
+    a = pTos->i;
+    b = pNos->i;
     switch( pOp->opcode ){
       case OP_Add:         b += a;       break;
       case OP_Subtract:    b -= a;       break;
@@ -1048,16 +1045,17 @@ case OP_Remainder: {
         break;
       }
     }
-    POPSTACK;
-    Release(p, nos);
-    aStack[nos].i = b;
-    aStack[nos].flags = MEM_Int;
+    Release(pTos);
+    pTos--;
+    Release(pTos);
+    pTos->i = b;
+    pTos->flags = MEM_Int;
   }else{
     double a, b;
-    Realify(p, tos);
-    Realify(p, nos);
-    a = aStack[tos].r;
-    b = aStack[nos].r;
+    Realify(pTos);
+    Realify(pNos);
+    a = pTos->r;
+    b = pNos->r;
     switch( pOp->opcode ){
       case OP_Add:         b += a;       break;
       case OP_Subtract:    b -= a;       break;
@@ -1075,17 +1073,19 @@ case OP_Remainder: {
         break;
       }
     }
-    POPSTACK;
-    Release(p, nos);
-    aStack[nos].r = b;
-    aStack[nos].flags = MEM_Real;
+    Release(pTos);
+    pTos--;
+    Release(pTos);
+    pTos->r = b;
+    pTos->flags = MEM_Real;
   }
   break;
 
 divide_by_zero:
-  sqliteVdbePopStack(p, 2);
-  p->tos = nos;
-  aStack[nos].flags = MEM_Null;
+  Release(pTos);
+  pTos--;
+  Release(pTos);
+  pTos->flags = MEM_Null;
   break;
 }
 
@@ -1099,18 +1099,20 @@ divide_by_zero:
 */
 case OP_Function: {
   int n, i;
+  Mem *pArg;
+  char **azArgv;
   sqlite_func ctx;
 
   n = pOp->p1;
-  VERIFY( if( n<0 ) goto bad_instruction; )
-  VERIFY( if( p->tos+1<n ) goto not_enough_stack; )
-  for(i=p->tos-n+1; i<=p->tos; i++){
-    if( aStack[i].flags & MEM_Null ){
-      aStack[i].z = 0;
+  pArg = &pTos[1-n];
+  azArgv = p->zArgv;
+  for(i=0; i<n; i++, pArg++){
+    if( pArg->flags & MEM_Null ){
+      azArgv[i] = 0;
     }else{
-      Stringify(p, i);
+      Stringify(pArg);
+      azArgv[i] = pArg->z;
     }
-    p->zArgv[i] = aStack[i].z;
   }
   ctx.pFunc = (FuncDef*)pOp->p3;
   ctx.s.flags = MEM_Null;
@@ -1118,21 +1120,17 @@ case OP_Function: {
   ctx.isError = 0;
   ctx.isStep = 0;
   if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
-  (*ctx.pFunc->xFunc)(&ctx, n, (const char**)&p->zArgv[p->tos-n+1]);
+  (*ctx.pFunc->xFunc)(&ctx, n, (const char**)azArgv);
   if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
-  sqliteVdbePopStack(p, n);
-  p->tos++;
-  aStack[p->tos] = ctx.s;
-  if( ctx.s.flags & MEM_Dyn ){
-    aStack[p->tos].z = ctx.s.z;
-  }else if( ctx.s.flags & MEM_Str ){
-    aStack[p->tos].z = aStack[p->tos].zShort;
-  }else{
-    aStack[p->tos].z = 0;
+  popStack(&pTos, n);
+  pTos++;
+  *pTos = ctx.s;
+  if( pTos->flags & MEM_Short ){
+    pTos->z = pTos->zShort;
   }
   if( ctx.isError ){
     sqliteSetString(&p->zErrMsg, 
-       aStack[p->tos].z ? aStack[p->tos].z : "user function error", (char*)0);
+       (pTos->flags & MEM_Str)!=0 ? pTos->z : "user function error", (char*)0);
     rc = SQLITE_ERROR;
   }
   break;
@@ -1170,20 +1168,20 @@ case OP_BitAnd:
 case OP_BitOr:
 case OP_ShiftLeft:
 case OP_ShiftRight: {
-  int tos = p->tos;
-  int nos = tos - 1;
+  Mem *pNos = &pTos[-1];
   int a, b;
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  if( (aStack[tos].flags | aStack[nos].flags) & MEM_Null ){
-    POPSTACK;
-    Release(p,nos);
-    aStack[nos].flags = MEM_Null;
+
+  assert( pNos>=p->aStack );
+  if( (pTos->flags | pNos->flags) & MEM_Null ){
+    popStack(&pTos, 2);
+    pTos++;
+    pTos->flags = MEM_Null;
     break;
   }
-  Integerify(p, tos);
-  Integerify(p, nos);
-  a = aStack[tos].i;
-  b = aStack[nos].i;
+  Integerify(pTos);
+  Integerify(pNos);
+  a = pTos->i;
+  b = pNos->i;
   switch( pOp->opcode ){
     case OP_BitAnd:      a &= b;     break;
     case OP_BitOr:       a |= b;     break;
@@ -1191,10 +1189,11 @@ case OP_ShiftRight: {
     case OP_ShiftRight:  a >>= b;    break;
     default:   /* CANT HAPPEN */     break;
   }
-  POPSTACK;
-  Release(p, nos);
-  aStack[nos].i = a;
-  aStack[nos].flags = MEM_Int;
+  assert( (pTos->flags & MEM_Dyn)==0 );
+  assert( (pNos->flags & MEM_Dyn)==0 );
+  pTos--;
+  pTos->i = a;
+  assert( pTos->flags==MEM_Int );
   break;
 }
 
@@ -1206,10 +1205,9 @@ case OP_ShiftRight: {
 ** To force the top of the stack to be an integer, just add 0.
 */
 case OP_AddImm: {
-  int tos = p->tos;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  Integerify(p, tos);
-  aStack[tos].i += pOp->p1;
+  assert( pTos>=p->aStack );
+  Integerify(pTos);
+  pTos->i += pOp->p1;
   break;
 }
 
@@ -1224,27 +1222,26 @@ case OP_AddImm: {
 ** greater than its current value if P1==1.
 */
 case OP_ForceInt: {
-  int tos = p->tos;
   int v;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( (aStack[tos].flags & (MEM_Int|MEM_Real))==0
-         && (aStack[tos].z==0 || sqliteIsNumber(aStack[tos].z)==0) ){
-    POPSTACK;
+  assert( pTos>=p->aStack );
+  if( (pTos->flags & (MEM_Int|MEM_Real))==0
+         && ((pTos->flags & MEM_Str)==0 || sqliteIsNumber(pTos->z)==0) ){
+    Release(pTos);
+    pTos--;
     pc = pOp->p2 - 1;
     break;
   }
-  if( aStack[tos].flags & MEM_Int ){
-    v = aStack[tos].i + (pOp->p1!=0);
+  if( pTos->flags & MEM_Int ){
+    v = pTos->i + (pOp->p1!=0);
   }else{
-    Realify(p, tos);
-    v = (int)aStack[tos].r;
-    if( aStack[tos].r>(double)v ) v++;
-    if( pOp->p1 && aStack[tos].r==(double)v ) v++;
-  }
-  if( aStack[tos].flags & MEM_Dyn ) sqliteFree(aStack[tos].z);
-  aStack[tos].z = 0;
-  aStack[tos].i = v;
-  aStack[tos].flags = MEM_Int;
+    Realify(pTos);
+    v = (int)pTos->r;
+    if( pTos->r>(double)v ) v++;
+    if( pOp->p1 && pTos->r==(double)v ) v++;
+  }
+  Release(pTos);
+  pTos->i = v;
+  pTos->flags = MEM_Int;
   break;
 }
 
@@ -1260,38 +1257,36 @@ case OP_ForceInt: {
 ** of the stack is unchanged.
 */
 case OP_MustBeInt: {
-  int tos = p->tos;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( aStack[tos].flags & MEM_Int ){
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Int ){
     /* Do nothing */
-  }else if( aStack[tos].flags & MEM_Real ){
-    int i = aStack[tos].r;
+  }else if( pTos->flags & MEM_Real ){
+    int i = (int)pTos->r;
     double r = (double)i;
-    if( r!=aStack[tos].r ){
+    if( r!=pTos->r ){
       goto mismatch;
     }
-    aStack[tos].i = i;
-  }else if( aStack[tos].flags & MEM_Str ){
+    pTos->i = i;
+  }else if( pTos->flags & MEM_Str ){
     int v;
-    if( !toInt(aStack[tos].z, &v) ){
+    if( !toInt(pTos->z, &v) ){
       double r;
-      if( !sqliteIsNumber(aStack[tos].z) ){
+      if( !sqliteIsNumber(pTos->z) ){
         goto mismatch;
       }
-      Realify(p, tos);
-      assert( (aStack[tos].flags & MEM_Real)!=0 );
-      v = aStack[tos].r;
+      Realify(pTos);
+      v = (int)pTos->r;
       r = (double)v;
-      if( r!=aStack[tos].r ){
+      if( r!=pTos->r ){
         goto mismatch;
       }
     }
-    aStack[tos].i = v;
+    pTos->i = v;
   }else{
     goto mismatch;
   }
-  Release(p, tos);
-  aStack[tos].flags = MEM_Int;
+  Release(pTos);
+  pTos->flags = MEM_Int;
   break;
 
 mismatch:
@@ -1299,7 +1294,7 @@ mismatch:
     rc = SQLITE_MISMATCH;
     goto abort_due_to_error;
   }else{
-    if( pOp->p1 ) POPSTACK;
+    if( pOp->p1 ) popStack(&pTos, 1);
     pc = pOp->p2 - 1;
   }
   break;
@@ -1422,39 +1417,31 @@ case OP_Lt:
 case OP_Le:
 case OP_Gt:
 case OP_Ge: {
-  int tos = p->tos;
-  int nos = tos - 1;
+  Mem *pNos = &pTos[-1];
   int c, v;
   int ft, fn;
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  ft = aStack[tos].flags;
-  fn = aStack[nos].flags;
+  assert( pNos>=p->aStack );
+  ft = pTos->flags;
+  fn = pNos->flags;
   if( (ft | fn) & MEM_Null ){
-    POPSTACK;
-    POPSTACK;
+    popStack(&pTos, 2);
     if( pOp->p2 ){
       if( pOp->p1 ) pc = pOp->p2-1;
     }else{
-      p->tos++;
-      aStack[nos].flags = MEM_Null;
+      pTos++;
+      pTos->flags = MEM_Null;
     }
     break;
   }else if( (ft & fn & MEM_Int)==MEM_Int ){
-    c = aStack[nos].i - aStack[tos].i;
-  }else if( (ft & MEM_Int)!=0 && (fn & MEM_Str)!=0 && toInt(aStack[nos].z,&v) ){
-    Release(p, nos);
-    aStack[nos].i = v;
-    aStack[nos].flags = MEM_Int;
-    c = aStack[nos].i - aStack[tos].i;
-  }else if( (fn & MEM_Int)!=0 && (ft & MEM_Str)!=0 && toInt(aStack[tos].z,&v) ){
-    Release(p, tos);
-    aStack[tos].i = v;
-    aStack[tos].flags = MEM_Int;
-    c = aStack[nos].i - aStack[tos].i;
+    c = pNos->i - pTos->i;
+  }else if( (ft & MEM_Int)!=0 && (fn & MEM_Str)!=0 && toInt(pNos->z,&v) ){
+    c = v - pTos->i;
+  }else if( (fn & MEM_Int)!=0 && (ft & MEM_Str)!=0 && toInt(pTos->z,&v) ){
+    c = pNos->i - v;
   }else{
-    Stringify(p, tos);
-    Stringify(p, nos);
-    c = sqliteCompare(aStack[nos].z, aStack[tos].z);
+    Stringify(pTos);
+    Stringify(pNos);
+    c = sqliteCompare(pNos->z, pTos->z);
   }
   switch( pOp->opcode ){
     case OP_Eq:    c = c==0;     break;
@@ -1464,14 +1451,13 @@ case OP_Ge: {
     case OP_Gt:    c = c>0;      break;
     default:       c = c>=0;     break;
   }
-  POPSTACK;
-  POPSTACK;
+  popStack(&pTos, 2);
   if( pOp->p2 ){
     if( c ) pc = pOp->p2-1;
   }else{
-    p->tos++;
-    aStack[nos].flags = MEM_Int;
-    aStack[nos].i = c;
+    pTos++;
+    pTos->i = c;
+    pTos->flags = MEM_Int;
   }
   break;
 }
@@ -1588,24 +1574,22 @@ case OP_StrLt:
 case OP_StrLe:
 case OP_StrGt:
 case OP_StrGe: {
-  int tos = p->tos;
-  int nos = tos - 1;
+  Mem *pNos = &pTos[-1];
   int c;
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  if( (aStack[nos].flags | aStack[tos].flags) & MEM_Null ){
-    POPSTACK;
-    POPSTACK;
+  assert( pNos>=p->aStack );
+  if( (pNos->flags | pTos->flags) & MEM_Null ){
+    popStack(&pTos, 2);
     if( pOp->p2 ){
       if( pOp->p1 ) pc = pOp->p2-1;
     }else{
-      p->tos++;
-      aStack[nos].flags = MEM_Null;
+      pTos++;
+      pTos->flags = MEM_Null;
     }
     break;
   }else{
-    Stringify(p, tos);
-    Stringify(p, nos);
-    c = strcmp(aStack[nos].z, aStack[tos].z);
+    Stringify(pTos);
+    Stringify(pNos);
+    c = strcmp(pNos->z, pTos->z);
   }
   /* The asserts on each case of the following switch are there to verify
   ** that string comparison opcodes are always exactly 6 greater than the
@@ -1620,14 +1604,13 @@ case OP_StrGe: {
     case OP_StrGt:    c = c>0;     assert( pOp->opcode-6==OP_Gt );   break;
     default:          c = c>=0;    assert( pOp->opcode-6==OP_Ge );   break;
   }
-  POPSTACK;
-  POPSTACK;
+  popStack(&pTos, 2);
   if( pOp->p2 ){
     if( c ) pc = pOp->p2-1;
   }else{
-    p->tos++;
-    aStack[nos].flags = MEM_Int;
-    aStack[nos].i = c;
+    pTos++;
+    pTos->flags = MEM_Int;
+    pTos->i = c;
   }
   break;
 }
@@ -1646,22 +1629,21 @@ case OP_StrGe: {
 */
 case OP_And:
 case OP_Or: {
-  int tos = p->tos;
-  int nos = tos - 1;
+  Mem *pNos = &pTos[-1];
   int v1, v2;    /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
 
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  if( aStack[tos].flags & MEM_Null ){
+  assert( pNos>=p->aStack );
+  if( pTos->flags & MEM_Null ){
     v1 = 2;
   }else{
-    Integerify(p, tos);
-    v1 = aStack[tos].i==0;
+    Integerify(pTos);
+    v1 = pTos->i==0;
   }
-  if( aStack[nos].flags & MEM_Null ){
+  if( pNos->flags & MEM_Null ){
     v2 = 2;
   }else{
-    Integerify(p, nos);
-    v2 = aStack[nos].i==0;
+    Integerify(pNos);
+    v2 = pNos->i==0;
   }
   if( pOp->opcode==OP_And ){
     static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
@@ -1670,13 +1652,13 @@ case OP_Or: {
     static const unsigned char or_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
     v1 = or_logic[v1*3+v2];
   }
-  POPSTACK;
-  Release(p, nos);
+  popStack(&pTos, 2);
+  pTos++;
   if( v1==2 ){
-    aStack[nos].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }else{
-    aStack[nos].i = v1==0;
-    aStack[nos].flags = MEM_Int;
+    pTos->i = v1==0;
+    pTos->flags = MEM_Int;
   }
   break;
 }
@@ -1695,29 +1677,28 @@ case OP_Or: {
 */
 case OP_Negative:
 case OP_AbsValue: {
-  int tos = p->tos;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( aStack[tos].flags & MEM_Real ){
-    Release(p, tos);
-    if( pOp->opcode==OP_Negative || aStack[tos].r<0.0 ){
-      aStack[tos].r = -aStack[tos].r;
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Real ){
+    Release(pTos);
+    if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
+      pTos->r = -pTos->r;
     }
-    aStack[tos].flags = MEM_Real;
-  }else if( aStack[tos].flags & MEM_Int ){
-    Release(p, tos);
-    if( pOp->opcode==OP_Negative ||  aStack[tos].i<0 ){
-      aStack[tos].i = -aStack[tos].i;
+    pTos->flags = MEM_Real;
+  }else if( pTos->flags & MEM_Int ){
+    Release(pTos);
+    if( pOp->opcode==OP_Negative || pTos->i<0 ){
+      pTos->i = -pTos->i;
     }
-    aStack[tos].flags = MEM_Int;
-  }else if( aStack[tos].flags & MEM_Null ){
+    pTos->flags = MEM_Int;
+  }else if( pTos->flags & MEM_Null ){
     /* Do nothing */
   }else{
-    Realify(p, tos);
-    Release(p, tos);
-    if( pOp->opcode==OP_Negative ||  aStack[tos].r<0.0 ){
-      aStack[tos].r = -aStack[tos].r;
+    Realify(pTos);
+    Release(pTos);
+    if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
+      pTos->r = -pTos->r;
     }
-    aStack[tos].flags = MEM_Real;
+    pTos->flags = MEM_Real;
   }
   break;
 }
@@ -1729,13 +1710,11 @@ case OP_AbsValue: {
 ** is unchanged.
 */
 case OP_Not: {
-  int tos = p->tos;
-  VERIFY( if( p->tos<0 ) goto not_enough_stack; )
-  if( aStack[tos].flags & MEM_Null ) break;  /* Do nothing to NULLs */
-  Integerify(p, tos);
-  Release(p, tos);
-  aStack[tos].i = !aStack[tos].i;
-  aStack[tos].flags = MEM_Int;
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ) break;  /* Do nothing to NULLs */
+  Integerify(pTos);
+  assert( pTos->flags==MEM_Int );
+  pTos->i = !pTos->i;
   break;
 }
 
@@ -1746,13 +1725,11 @@ case OP_Not: {
 ** value is unchanged.
 */
 case OP_BitNot: {
-  int tos = p->tos;
-  VERIFY( if( p->tos<0 ) goto not_enough_stack; )
-  if( aStack[tos].flags & MEM_Null ) break;  /* Do nothing to NULLs */
-  Integerify(p, tos);
-  Release(p, tos);
-  aStack[tos].i = ~aStack[tos].i;
-  aStack[tos].flags = MEM_Int;
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ) break;  /* Do nothing to NULLs */
+  Integerify(pTos);
+  assert( pTos->flags==MEM_Int );
+  pTos->i = ~pTos->i;
   break;
 }
 
@@ -1788,15 +1765,16 @@ case OP_Noop: {
 case OP_If:
 case OP_IfNot: {
   int c;
-  VERIFY( if( p->tos<0 ) goto not_enough_stack; )
-  if( aStack[p->tos].flags & MEM_Null ){
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ){
     c = pOp->p1;
   }else{
-    Integerify(p, p->tos);
-    c = aStack[p->tos].i;
+    Integerify(pTos);
+    c = pTos->i;
     if( pOp->opcode==OP_IfNot ) c = !c;
   }
-  POPSTACK;
+  assert( (pTos->flags & MEM_Dyn)==0 );
+  pTos--;
   if( c ) pc = pOp->p2-1;
   break;
 }
@@ -1809,16 +1787,18 @@ case OP_IfNot: {
 */
 case OP_IsNull: {
   int i, cnt;
+  Mem *pTerm;
   cnt = pOp->p1;
   if( cnt<0 ) cnt = -cnt;
-  VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; )
-  for(i=0; i<cnt; i++){
-    if( aStack[p->tos-i].flags & MEM_Null ){
+  pTerm = &pTos[1-cnt];
+  assert( pTerm>=p->aStack );
+  for(i=0; i<cnt; i++, pTerm++){
+    if( pTerm->flags & MEM_Null ){
       pc = pOp->p2-1;
       break;
     }
   }
-  if( pOp->p1>0 ) sqliteVdbePopStack(p, cnt);
+  if( pOp->p1>0 ) popStack(&pTos, cnt);
   break;
 }
 
@@ -1832,10 +1812,10 @@ case OP_NotNull: {
   int i, cnt;
   cnt = pOp->p1;
   if( cnt<0 ) cnt = -cnt;
-  VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; )
-  for(i=0; i<cnt && (aStack[p->tos-i].flags & MEM_Null)==0; i++){}
+  assert( &pTos[1-cnt] >= p->aStack );
+  for(i=0; i<cnt && (pTos[1+i-cnt].flags & MEM_Null)==0; i++){}
   if( i>=cnt ) pc = pOp->p2-1;
-  if( pOp->p1>0 ) sqliteVdbePopStack(p, cnt);
+  if( pOp->p1>0 ) popStack(&pTos, cnt);
   break;
 }
 
@@ -1867,6 +1847,7 @@ case OP_MakeRecord: {
   int i, j;
   int idxWidth;
   u32 addr;
+  Mem *pRec;
   int addUnique = 0;   /* True to cause bytes to be added to make the
                        ** generated record distinct */
   char zTemp[NBFS];    /* Temp space for small records */
@@ -1890,14 +1871,15 @@ case OP_MakeRecord: {
   ** Idx(N) contains the total number of bytes in the record.
   */
   nField = pOp->p1;
-  VERIFY( if( p->tos+1<nField ) goto not_enough_stack; )
+  pRec = &pTos[1-nField];
+  assert( pRec>=p->aStack );
   nByte = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( (aStack[i].flags & MEM_Null) ){
+  for(i=0; i<nField; i++, pRec++){
+    if( pRec->flags & MEM_Null ){
       addUnique = pOp->p2;
     }else{
-      Stringify(p, i);
-      nByte += aStack[i].n;
+      Stringify(pRec);
+      nByte += pRec->n;
     }
   }
   if( addUnique ) nByte += sizeof(p->uniqueCnt);
@@ -1921,7 +1903,7 @@ case OP_MakeRecord: {
   }
   j = 0;
   addr = idxWidth*(nField+1) + addUnique*sizeof(p->uniqueCnt);
-  for(i=p->tos-nField+1; i<=p->tos; i++){
+  for(i=0, pRec=&pTos[1-nField]; i<nField; i++, pRec++){
     zNewRecord[j++] = addr & 0xff;
     if( idxWidth>1 ){
       zNewRecord[j++] = (addr>>8)&0xff;
@@ -1929,8 +1911,8 @@ case OP_MakeRecord: {
         zNewRecord[j++] = (addr>>16)&0xff;
       }
     }
-    if( (aStack[i].flags & MEM_Null)==0 ){
-      addr += aStack[i].n;
+    if( (pRec->flags & MEM_Null)==0 ){
+      addr += pRec->n;
     }
   }
   zNewRecord[j++] = addr & 0xff;
@@ -1945,24 +1927,24 @@ case OP_MakeRecord: {
     p->uniqueCnt++;
     j += sizeof(p->uniqueCnt);
   }
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( (aStack[i].flags & MEM_Null)==0 ){
-      memcpy(&zNewRecord[j], aStack[i].z, aStack[i].n);
-      j += aStack[i].n;
+  for(i=0, pRec=&pTos[1-nField]; i<nField; i++, pRec++){
+    if( (pRec->flags & MEM_Null)==0 ){
+      memcpy(&zNewRecord[j], pRec->z, pRec->n);
+      j += pRec->n;
     }
   }
-  sqliteVdbePopStack(p, nField);
-  p->tos++;
-  aStack[p->tos].n = nByte;
+  popStack(&pTos, nField);
+  pTos++;
+  pTos->n = nByte;
   if( nByte<=NBFS ){
     assert( zNewRecord==zTemp );
-    memcpy(aStack[p->tos].zShort, zTemp, nByte);
-    aStack[p->tos].z = aStack[p->tos].zShort;
-    aStack[p->tos].flags = MEM_Str;
+    memcpy(pTos->zShort, zTemp, nByte);
+    pTos->z = pTos->zShort;
+    pTos->flags = MEM_Str | MEM_Short;
   }else{
     assert( zNewRecord!=zTemp );
-    aStack[p->tos].flags = MEM_Str | MEM_Dyn;
-    aStack[p->tos].z = zNewRecord;
+    pTos->z = zNewRecord;
+    pTos->flags = MEM_Str | MEM_Dyn;
   }
   break;
 }
@@ -2047,39 +2029,41 @@ case OP_MakeKey: {
   int addRowid;
   int i, j;
   int containsNull = 0;
+  Mem *pRec;
   char zTemp[NBFS];
 
   addRowid = pOp->opcode==OP_MakeIdxKey;
   nField = pOp->p1;
-  VERIFY( if( p->tos+1+addRowid<nField ) goto not_enough_stack; )
+  pRec = &pTos[1-nField];
+  assert( pRec>=p->aStack );
   nByte = 0;
-  for(j=0, i=p->tos-nField+1; i<=p->tos; i++, j++){
-    int flags = aStack[i].flags;
+  for(j=0, i=0; i<nField; i++, j++, pRec++){
+    int flags = pRec->flags;
     int len;
     char *z;
     if( flags & MEM_Null ){
       nByte += 2;
       containsNull = 1;
     }else if( pOp->p3 && pOp->p3[j]=='t' ){
-      Stringify(p, i);
-      aStack[i].flags &= ~(MEM_Int|MEM_Real);
-      nByte += aStack[i].n+1;
-    }else if( (flags & (MEM_Real|MEM_Int))!=0 || sqliteIsNumber(aStack[i].z) ){
+      Stringify(pRec);
+      pRec->flags &= ~(MEM_Int|MEM_Real);
+      nByte += pRec->n+1;
+    }else if( (flags & (MEM_Real|MEM_Int))!=0 || sqliteIsNumber(pRec->z) ){
       if( (flags & (MEM_Real|MEM_Int))==MEM_Int ){
-        aStack[i].r = aStack[i].i;
+        pRec->r = pRec->i;
       }else if( (flags & (MEM_Real|MEM_Int))==0 ){
-        aStack[i].r = sqliteAtoF(aStack[i].z);
+        pRec->r = sqliteAtoF(pRec->z);
       }
-      Release(p, i);
-      z = aStack[i].zShort;
-      sqliteRealToSortable(aStack[i].r, z);
+      Release(pRec);
+      z = pRec->zShort;
+      sqliteRealToSortable(pRec->r, z);
       len = strlen(z);
-      aStack[i].z = 0;
-      aStack[i].flags = MEM_Real;
-      aStack[i].n = len+1;
-      nByte += aStack[i].n+1;
+      pRec->z = 0;
+      pRec->flags = MEM_Real;
+      pRec->n = len+1;
+      nByte += pRec->n+1;
     }else{
-      nByte += aStack[i].n+1;
+      nByte += pRec->n+1;
     }
   }
   if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){
@@ -2094,41 +2078,44 @@ case OP_MakeKey: {
     if( zNewKey==0 ) goto no_mem;
   }
   j = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( aStack[i].flags & MEM_Null ){
+  pRec = &pTos[1-nField];
+  for(i=0; i<nField; i++, pRec++){
+    if( pRec->flags & MEM_Null ){
       zNewKey[j++] = 'a';
       zNewKey[j++] = 0;
+    }else if( pRec->flags==MEM_Real ){
+      zNewKey[j++] = 'b';
+      memcpy(&zNewKey[j], pRec->zShort, pRec->n);
+      j += pRec->n;
     }else{
-      if( aStack[i].flags & (MEM_Int|MEM_Real) ){
-        zNewKey[j++] = 'b';
-      }else{
-        zNewKey[j++] = 'c';
-      }
-      /*** Is this right? ****/
-      memcpy(&zNewKey[j],aStack[i].z?aStack[i].z:aStack[i].zShort,aStack[i].n);
-      j += aStack[i].n;
+      assert( pRec->flags & MEM_Str );
+      zNewKey[j++] = 'c';
+      memcpy(&zNewKey[j], pRec->z, pRec->n);
+      j += pRec->n;
     }
   }
   if( addRowid ){
     u32 iKey;
-    Integerify(p, p->tos-nField);
-    iKey = intToKey(aStack[p->tos-nField].i);
+    pRec = &pTos[-nField];
+    assert( pRec>=p->aStack );
+    Integerify(pRec);
+    iKey = intToKey(pRec->i);
     memcpy(&zNewKey[j], &iKey, sizeof(u32));
-    sqliteVdbePopStack(p, nField+1);
+    popStack(&pTos, nField+1);
     if( pOp->p2 && containsNull ) pc = pOp->p2 - 1;
   }else{
-    if( pOp->p2==0 ) sqliteVdbePopStack(p, nField+addRowid);
+    if( pOp->p2==0 ) popStack(&pTos, nField);
   }
-  p->tos++;
-  aStack[p->tos].n = nByte;
+  pTos++;
+  pTos->n = nByte;
   if( nByte<=NBFS ){
     assert( zNewKey==zTemp );
-    aStack[p->tos].z = aStack[p->tos].zShort;
-    memcpy(aStack[p->tos].z, zTemp, nByte);
-    aStack[p->tos].flags = MEM_Str;
+    pTos->z = pTos->zShort;
+    memcpy(pTos->zShort, zTemp, nByte);
+    pTos->flags = MEM_Str | MEM_Short;
   }else{
-    aStack[p->tos].flags = MEM_Str|MEM_Dyn;
-    aStack[p->tos].z = zNewKey;
+    pTos->z = zNewKey;
+    pTos->flags = MEM_Str | MEM_Dyn;
   }
   break;
 }
@@ -2142,18 +2129,14 @@ case OP_MakeKey: {
 ** the key itself.
 */
 case OP_IncrKey: {
-  int tos = p->tos;
-
-  VERIFY( if( tos<0 ) goto bad_instruction );
-  Stringify(p, tos);
-  if( aStack[tos].flags & (MEM_Static|MEM_Ephem) ){
-    /* CANT HAPPEN.  The IncrKey opcode is only applied to keys
-    ** generated by MakeKey or MakeIdxKey and the results of those
-    ** operands are always dynamic strings.
-    */
-    goto abort_due_to_error;
-  }
-  aStack[tos].z[aStack[tos].n-1]++;
+  assert( pTos>=p->aStack );
+  /* The IncrKey opcode is only applied to keys generated by
+  ** MakeKey or MakeIdxKey and the results of those operands
+  ** are always dynamic strings or zShort[] strings.  So we
+  ** are always free to modify the string in place.
+  */
+  assert( pTos->flags & (MEM_Dyn|MEM_Short) );
+  pTos->z[pTos->n-1]++;
   break;
 }
 
@@ -2206,6 +2189,7 @@ case OP_Transaction: {
           p->pc = pc;
           p->undoTransOnError = 1;
           p->rc = SQLITE_BUSY;
+          p->pTos = pTos;
           return SQLITE_BUSY;
         }else if( (*db->xBusyCallback)(db->pBusyArg, "", busy++)==0 ){
           sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
@@ -2295,14 +2279,14 @@ case OP_Rollback: {
 ** executing this instruction.
 */
 case OP_ReadCookie: {
-  int i = ++p->tos;
   int aMeta[SQLITE_N_BTREE_META];
   assert( pOp->p2<SQLITE_N_BTREE_META );
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( db->aDb[pOp->p1].pBt!=0 );
   rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
-  aStack[i].i = aMeta[1+pOp->p2];
-  aStack[i].flags = MEM_Int;
+  pTos++;
+  pTos->i = aMeta[1+pOp->p2];
+  pTos->flags = MEM_Int;
   break;
 }
 
@@ -2321,14 +2305,15 @@ case OP_SetCookie: {
   assert( pOp->p2<SQLITE_N_BTREE_META );
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( db->aDb[pOp->p1].pBt!=0 );
-  VERIFY( if( p->tos<0 ) goto not_enough_stack; )
-  Integerify(p, p->tos)
+  assert( pTos>=p->aStack );
+  Integerify(pTos)
   rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
   if( rc==SQLITE_OK ){
-    aMeta[1+pOp->p2] = aStack[p->tos].i;
+    aMeta[1+pOp->p2] = pTos->i;
     rc = sqliteBtreeUpdateMeta(db->aDb[pOp->p1].pBt, aMeta);
   }
-  POPSTACK;
+  assert( pTos->flags==MEM_Int );
+  pTos--;
   break;
 }
 
@@ -2407,32 +2392,31 @@ case OP_OpenRead:
 case OP_OpenWrite: {
   int busy = 0;
   int i = pOp->p1;
-  int tos = p->tos;
   int p2 = pOp->p2;
   int wrFlag;
   Btree *pX;
   int iDb;
   
-  VERIFY( if( tos<0 ) goto not_enough_stack; );
-  Integerify(p, tos);
-  iDb = p->aStack[tos].i;
-  tos--;
-  VERIFY( if( iDb<0 || iDb>=db->nDb ) goto bad_instruction; );
-  VERIFY( if( db->aDb[iDb].pBt==0 ) goto bad_instruction; );
+  assert( pTos>=p->aStack );
+  Integerify(pTos);
+  iDb = pTos->i;
+  pTos--;
+  assert( iDb>=0 && iDb<db->nDb );
   pX = db->aDb[iDb].pBt;
+  assert( pX!=0 );
   wrFlag = pOp->opcode==OP_OpenWrite;
   if( p2<=0 ){
-    VERIFY( if( tos<0 ) goto not_enough_stack; );
-    Integerify(p, tos);
-    p2 = p->aStack[tos].i;
-    POPSTACK;
+    assert( pTos>=p->aStack );
+    Integerify(pTos);
+    p2 = pTos->i;
+    pTos--;
     if( p2<2 ){
       sqliteSetString(&p->zErrMsg, "root page number less than 2", (char*)0);
       rc = SQLITE_INTERNAL;
       break;
     }
   }
-  VERIFY( if( i<0 ) goto bad_instruction; )
+  assert( i>=0 );
   if( expandCursorArraySize(p, i) ) goto no_mem;
   sqliteVdbeCleanupCursor(&p->aCsr[i]);
   memset(&p->aCsr[i], 0, sizeof(Cursor));
@@ -2445,6 +2429,7 @@ case OP_OpenWrite: {
         if( db->xBusyCallback==0 ){
           p->pc = pc;
           p->rc = SQLITE_BUSY;
+          p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
           return SQLITE_BUSY;
         }else if( (*db->xBusyCallback)(db->pBusyArg, pOp->p3, ++busy)==0 ){
           sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
@@ -2461,10 +2446,6 @@ case OP_OpenWrite: {
       }
     }
   }while( busy );
-  if( p2<=0 ){
-    POPSTACK;
-  }
-  POPSTACK;
   break;
 }
 
@@ -2489,7 +2470,7 @@ case OP_OpenWrite: {
 case OP_OpenTemp: {
   int i = pOp->p1;
   Cursor *pCx;
-  VERIFY( if( i<0 ) goto bad_instruction; )
+  assert( i>=0 );
   if( expandCursorArraySize(p, i) ) goto no_mem;
   pCx = &p->aCsr[i];
   sqliteVdbeCleanupCursor(pCx);
@@ -2527,7 +2508,7 @@ case OP_OpenTemp: {
 case OP_OpenPseudo: {
   int i = pOp->p1;
   Cursor *pCx;
-  VERIFY( if( i<0 ) goto bad_instruction; )
+  assert( i>=0 );
   if( expandCursorArraySize(p, i) ) goto no_mem;
   pCx = &p->aCsr[i];
   sqliteVdbeCleanupCursor(pCx);
@@ -2574,29 +2555,29 @@ case OP_Close: {
 case OP_MoveLt:
 case OP_MoveTo: {
   int i = pOp->p1;
-  int tos = p->tos;
   Cursor *pC;
 
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
+  assert( pTos>=p->aStack );
   assert( i>=0 && i<p->nCursor );
   pC = &p->aCsr[i];
   if( pC->pCursor!=0 ){
     int res, oc;
     pC->nullRow = 0;
-    if( aStack[tos].flags & MEM_Int ){
-      int iKey = intToKey(aStack[tos].i);
+    if( pTos->flags & MEM_Int ){
+      int iKey = intToKey(pTos->i);
       if( pOp->p2==0 && pOp->opcode==OP_MoveTo ){
         pC->movetoTarget = iKey;
         pC->deferredMoveto = 1;
-        POPSTACK;
+        Release(pTos);
+        pTos--;
         break;
       }
       sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
-      pC->lastRecno = aStack[tos].i;
+      pC->lastRecno = pTos->i;
       pC->recnoIsValid = res==0;
     }else{
-      Stringify(p, tos);
-      sqliteBtreeMoveto(pC->pCursor, aStack[tos].z, aStack[tos].n, &res);
+      Stringify(pTos);
+      sqliteBtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
       pC->recnoIsValid = 0;
     }
     pC->deferredMoveto = 0;
@@ -2624,7 +2605,8 @@ case OP_MoveTo: {
       }
     }
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -2665,14 +2647,14 @@ case OP_Distinct:
 case OP_NotFound:
 case OP_Found: {
   int i = pOp->p1;
-  int tos = p->tos;
   int alreadyExists = 0;
   Cursor *pC;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
+  assert( pTos>=p->aStack );
+  assert( i>=0 && i<p->nCursor );
+  if( (pC = &p->aCsr[i])->pCursor!=0 ){
     int res, rx;
-    Stringify(p, tos);
-    rx = sqliteBtreeMoveto(pC->pCursor, aStack[tos].z, aStack[tos].n, &res);
+    Stringify(pTos);
+    rx = sqliteBtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
     alreadyExists = rx==SQLITE_OK && res==0;
     pC->deferredMoveto = 0;
   }
@@ -2682,7 +2664,8 @@ case OP_Found: {
     if( !alreadyExists ) pc = pOp->p2 - 1;
   }
   if( pOp->opcode!=OP_Distinct ){
-    POPSTACK;
+    Release(pTos);
+    pTos--;
   }
   break;
 }
@@ -2709,18 +2692,18 @@ case OP_Found: {
 */
 case OP_IsUnique: {
   int i = pOp->p1;
-  int tos = p->tos;
-  int nos = tos-1;
+  Mem *pNos = &pTos[-1];
   BtCursor *pCrsr;
   int R;
 
   /* Pop the value R off the top of the stack
   */
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  Integerify(p, tos);
-  R = aStack[tos].i;   
-  POPSTACK;
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+  assert( pNos>=p->aStack );
+  Integerify(pTos);
+  R = pTos->i;
+  pTos--;
+  assert( i>=0 && i<=p->nCursor );
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int res, rc;
     int v;         /* The record number on the P1 entry that matches K */
     char *zKey;    /* The value of K */
@@ -2728,9 +2711,9 @@ case OP_IsUnique: {
 
     /* Make sure K is a string and make zKey point to K
     */
-    Stringify(p, nos);
-    zKey = aStack[nos].z;
-    nKey = aStack[nos].n;
+    Stringify(pNos);
+    zKey = pNos->z;
+    nKey = pNos->n;
     assert( nKey >= 4 );
 
     /* Search for an entry in P1 where all but the last four bytes match K.
@@ -2770,9 +2753,9 @@ case OP_IsUnique: {
     ** stack.  (These bytes are the record number of an entry that
     ** violates a UNIQUE constraint.)
     */
-    p->tos++;
-    aStack[tos].i = v;
-    aStack[tos].flags = MEM_Int;
+    pTos++;
+    pTos->i = v;
+    pTos->flags = MEM_Int;
   }
   break;
 }
@@ -2792,15 +2775,15 @@ case OP_IsUnique: {
 */
 case OP_NotExists: {
   int i = pOp->p1;
-  int tos = p->tos;
   BtCursor *pCrsr;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+  assert( pTos>=p->aStack );
+  assert( i>=0 && i<p->nCursor );
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int res, rx, iKey;
-    assert( aStack[tos].flags & MEM_Int );
-    iKey = intToKey(aStack[tos].i);
+    assert( pTos->flags & MEM_Int );
+    iKey = intToKey(pTos->i);
     rx = sqliteBtreeMoveto(pCrsr, (char*)&iKey, sizeof(int), &res);
-    p->aCsr[i].lastRecno = aStack[tos].i;
+    p->aCsr[i].lastRecno = pTos->i;
     p->aCsr[i].recnoIsValid = res==0;
     p->aCsr[i].nullRow = 0;
     if( rx!=SQLITE_OK || res!=0 ){
@@ -2808,7 +2791,8 @@ case OP_NotExists: {
       p->aCsr[i].recnoIsValid = 0;
     }
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -2823,7 +2807,8 @@ case OP_NewRecno: {
   int i = pOp->p1;
   int v = 0;
   Cursor *pC;
-  if( VERIFY( i<0 || i>=p->nCursor || ) (pC = &p->aCsr[i])->pCursor==0 ){
+  assert( i>=0 && i<p->nCursor );
+  if( (pC = &p->aCsr[i])->pCursor==0 ){
     v = 0;
   }else{
     /* The next rowid or record number (different terms for the same
@@ -2907,9 +2892,9 @@ case OP_NewRecno: {
     pC->recnoIsValid = 0;
     pC->deferredMoveto = 0;
   }
-  p->tos++;
-  aStack[p->tos].i = v;
-  aStack[p->tos].flags = MEM_Int;
+  pTos++;
+  pTos->i = v;
+  pTos->flags = MEM_Int;
   break;
 }
 
@@ -2937,29 +2922,28 @@ case OP_NewRecno: {
 */
 case OP_PutIntKey:
 case OP_PutStrKey: {
-  int tos = p->tos;
-  int nos = p->tos-1;
+  Mem *pNos = &pTos[-1];
   int i = pOp->p1;
   Cursor *pC;
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  if( VERIFY( i>=0 && i<p->nCursor && )
-      ((pC = &p->aCsr[i])->pCursor!=0 || pC->pseudoTable) ){
+  assert( pNos>=p->aStack );
+  assert( i>=0 && i<p->nCursor );
+  if( ((pC = &p->aCsr[i])->pCursor!=0 || pC->pseudoTable) ){
     char *zKey;
     int nKey, iKey;
     if( pOp->opcode==OP_PutStrKey ){
-      Stringify(p, nos);
-      nKey = aStack[nos].n;
-      zKey = aStack[nos].z;
+      Stringify(pNos);
+      nKey = pNos->n;
+      zKey = pNos->z;
     }else{
-      assert( aStack[nos].flags & MEM_Int );
+      assert( pNos->flags & MEM_Int );
       nKey = sizeof(int);
-      iKey = intToKey(aStack[nos].i);
+      iKey = intToKey(pNos->i);
       zKey = (char*)&iKey;
       if( pOp->p2 ){
         db->nChange++;
-        db->lastRowid = aStack[nos].i;
+        db->lastRowid = pNos->i;
       }
-      if( pC->nextRowidValid && aStack[nos].i>=pC->nextRowid ){
+      if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
         pC->nextRowidValid = 0;
       }
     }
@@ -2971,27 +2955,24 @@ case OP_PutStrKey: {
       assert( pOp->opcode==OP_PutIntKey );
       sqliteFree(pC->pData);
       pC->iKey = iKey;
-      pC->nData = aStack[tos].n;
-      if( aStack[tos].flags & MEM_Dyn ){
-        pC->pData = aStack[tos].z;
-        aStack[tos].z = 0;
-        aStack[tos].flags = MEM_Null;
+      pC->nData = pTos->n;
+      if( pTos->flags & MEM_Dyn ){
+        pC->pData = pTos->z;
+        pTos->flags = MEM_Null;
       }else{
         pC->pData = sqliteMallocRaw( pC->nData );
         if( pC->pData ){
-          memcpy(pC->pData, aStack[tos].z, pC->nData);
+          memcpy(pC->pData, pTos->z, pC->nData);
         }
       }
       pC->nullRow = 0;
     }else{
-      rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey,
-                          aStack[tos].z, aStack[tos].n);
+      rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey, pTos->z, pTos->n);
     }
     pC->recnoIsValid = 0;
     pC->deferredMoveto = 0;
   }
-  POPSTACK;
-  POPSTACK;
+  popStack(&pTos, 2);
   break;
 }
 
@@ -3058,46 +3039,46 @@ case OP_KeyAsData: {
 case OP_RowKey:
 case OP_RowData: {
   int i = pOp->p1;
-  int tos = ++p->tos;
   Cursor *pC;
   int n;
 
+  pTos++;
   assert( i>=0 && i<p->nCursor );
   pC = &p->aCsr[i];
   if( pC->nullRow ){
-    aStack[tos].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }else if( pC->pCursor!=0 ){
     BtCursor *pCrsr = pC->pCursor;
     sqliteVdbeCursorMoveto(pC);
     if( pC->nullRow ){
-      aStack[tos].flags = MEM_Null;
+      pTos->flags = MEM_Null;
       break;
     }else if( pC->keyAsData || pOp->opcode==OP_RowKey ){
       sqliteBtreeKeySize(pCrsr, &n);
     }else{
       sqliteBtreeDataSize(pCrsr, &n);
     }
-    aStack[tos].n = n;
+    pTos->n = n;
     if( n<=NBFS ){
-      aStack[tos].flags = MEM_Str;
-      aStack[tos].z = aStack[tos].zShort;
+      pTos->flags = MEM_Str | MEM_Short;
+      pTos->z = pTos->zShort;
     }else{
       char *z = sqliteMallocRaw( n );
       if( z==0 ) goto no_mem;
-      aStack[tos].flags = MEM_Str | MEM_Dyn;
-      aStack[tos].z = z;
+      pTos->flags = MEM_Str | MEM_Dyn;
+      pTos->z = z;
     }
     if( pC->keyAsData || pOp->opcode==OP_RowKey ){
-      sqliteBtreeKey(pCrsr, 0, n, aStack[tos].z);
+      sqliteBtreeKey(pCrsr, 0, n, pTos->z);
     }else{
-      sqliteBtreeData(pCrsr, 0, n, aStack[tos].z);
+      sqliteBtreeData(pCrsr, 0, n, pTos->z);
     }
   }else if( pC->pseudoTable ){
-    aStack[tos].n = pC->nData;
-    aStack[tos].z = pC->pData;
-    aStack[tos].flags = MEM_Str|MEM_Ephem;
+    pTos->n = pC->nData;
+    pTos->z = pC->pData;
+    pTos->flags = MEM_Str|MEM_Ephem;
   }else{
-    aStack[tos].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }
   break;
 }
@@ -3125,7 +3106,6 @@ case OP_Column: {
   int amt, offset, end, payloadSize;
   int i = pOp->p1;
   int p2 = pOp->p2;
-  int tos = p->tos+1;
   Cursor *pC;
   char *zRec;
   BtCursor *pCrsr;
@@ -3133,11 +3113,12 @@ case OP_Column: {
   unsigned char aHdr[10];
 
   assert( i<p->nCursor );
+  pTos++;
   if( i<0 ){
-    VERIFY( if( tos+i<0 ) goto bad_instruction; )
-    VERIFY( if( (aStack[tos+i].flags & MEM_Str)==0 ) goto bad_instruction; )
-    zRec = aStack[tos+i].z;
-    payloadSize = aStack[tos+i].n;
+    assert( &pTos[i]>=p->aStack );
+    assert( pTos[i].flags & MEM_Str );
+    zRec = pTos[i].z;
+    payloadSize = pTos[i].n;
   }else if( (pC = &p->aCsr[i])->pCursor!=0 ){
     sqliteVdbeCursorMoveto(pC);
     zRec = 0;
@@ -3161,8 +3142,7 @@ case OP_Column: {
   ** data begins.
   */
   if( payloadSize==0 ){
-    aStack[tos].flags = MEM_Null;
-    p->tos = tos;
+    pTos->flags = MEM_Null;
     break;
   }else if( payloadSize<256 ){
     idxWidth = 1;
@@ -3204,31 +3184,28 @@ case OP_Column: {
   /* amt and offset now hold the offset to the start of data and the
   ** amount of data.  Go get the data and put it on the stack.
   */
+  pTos->n = amt;
   if( amt==0 ){
-    aStack[tos].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }else if( zRec ){
-    aStack[tos].flags = MEM_Str | MEM_Ephem;
-    aStack[tos].n = amt;
-    aStack[tos].z = &zRec[offset];
+    pTos->flags = MEM_Str | MEM_Ephem;
+    pTos->z = &zRec[offset];
   }else{
     if( amt<=NBFS ){
-      aStack[tos].flags = MEM_Str;
-      aStack[tos].z = aStack[tos].zShort;
-      aStack[tos].n = amt;
+      pTos->flags = MEM_Str | MEM_Short;
+      pTos->z = pTos->zShort;
     }else{
       char *z = sqliteMallocRaw( amt );
       if( z==0 ) goto no_mem;
-      aStack[tos].flags = MEM_Str | MEM_Dyn;
-      aStack[tos].z = z;
-      aStack[tos].n = amt;
+      pTos->flags = MEM_Str | MEM_Dyn;
+      pTos->z = z;
     }
     if( pC->keyAsData ){
-      sqliteBtreeKey(pCrsr, offset, amt, aStack[tos].z);
+      sqliteBtreeKey(pCrsr, offset, amt, pTos->z);
     }else{
-      sqliteBtreeData(pCrsr, offset, amt, aStack[tos].z);
+      sqliteBtreeData(pCrsr, offset, amt, pTos->z);
     }
   }
-  p->tos = tos;
   break;
 }
 
@@ -3241,27 +3218,27 @@ case OP_Column: {
 */
 case OP_Recno: {
   int i = pOp->p1;
-  int tos = ++p->tos;
   Cursor *pC;
   int v;
 
   assert( i>=0 && i<p->nCursor );
   pC = &p->aCsr[i];
   sqliteVdbeCursorMoveto(pC);
+  pTos++;
   if( pC->recnoIsValid ){
     v = pC->lastRecno;
   }else if( pC->pseudoTable ){
     v = keyToInt(pC->iKey);
   }else if( pC->nullRow || pC->pCursor==0 ){
-    aStack[tos].flags = MEM_Null;
+    pTos->flags = MEM_Null;
     break;
   }else{
     assert( pC->pCursor!=0 );
     sqliteBtreeKey(pC->pCursor, 0, sizeof(u32), (char*)&v);
     v = keyToInt(v);
   }
-  aStack[tos].i = v;
-  aStack[tos].flags = MEM_Int;
+  pTos->i = v;
+  pTos->flags = MEM_Int;
   break;
 }
 
@@ -3278,12 +3255,13 @@ case OP_Recno: {
 */
 case OP_FullKey: {
   int i = pOp->p1;
-  int tos = ++p->tos;
   BtCursor *pCrsr;
 
-  VERIFY( if( !p->aCsr[i].keyAsData ) goto bad_instruction; )
-  VERIFY( if( p->aCsr[i].pseudoTable ) goto bad_instruction; )
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+  assert( p->aCsr[i].keyAsData );
+  assert( !p->aCsr[i].pseudoTable );
+  assert( i>=0 && i<p->nCursor );
+  pTos++;
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int amt;
     char *z;
 
@@ -3296,14 +3274,14 @@ case OP_FullKey: {
     if( amt>NBFS ){
       z = sqliteMallocRaw( amt );
       if( z==0 ) goto no_mem;
-      aStack[tos].flags = MEM_Str | MEM_Dyn;
+      pTos->flags = MEM_Str | MEM_Dyn;
     }else{
-      z = aStack[tos].zShort;
-      aStack[tos].flags = MEM_Str;
+      z = pTos->zShort;
+      pTos->flags = MEM_Str | MEM_Short;
     }
     sqliteBtreeKey(pCrsr, 0, amt, z);
-    aStack[tos].z = z;
-    aStack[tos].n = amt;
+    pTos->z = z;
+    pTos->n = amt;
   }
   break;
 }
@@ -3440,15 +3418,16 @@ case OP_Next: {
 */
 case OP_IdxPut: {
   int i = pOp->p1;
-  int tos = p->tos;
   BtCursor *pCrsr;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
-    int nKey = aStack[tos].n;
-    const char *zKey = aStack[tos].z;
+  assert( pTos>=p->aStack );
+  assert( i>=0 && i<p->nCursor );
+  assert( pTos->flags & MEM_Str );
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
+    int nKey = pTos->n;
+    const char *zKey = pTos->z;
     if( pOp->p2 ){
       int res, n;
-      assert( aStack[tos].n >= 4 );
+      assert( nKey >= 4 );
       rc = sqliteBtreeMoveto(pCrsr, zKey, nKey-4, &res);
       if( rc!=SQLITE_OK ) goto abort_due_to_error;
       while( res!=0 ){
@@ -3475,7 +3454,8 @@ case OP_IdxPut: {
     rc = sqliteBtreeInsert(pCrsr, zKey, nKey, "", 0);
     assert( p->aCsr[i].deferredMoveto==0 );
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -3486,18 +3466,20 @@ case OP_IdxPut: {
 */
 case OP_IdxDelete: {
   int i = pOp->p1;
-  int tos = p->tos;
   BtCursor *pCrsr;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+  assert( pTos>=p->aStack );
+  assert( pTos->flags & MEM_Str );
+  assert( i>=0 && i<p->nCursor );
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int rx, res;
-    rx = sqliteBtreeMoveto(pCrsr, aStack[tos].z, aStack[tos].n, &res);
+    rx = sqliteBtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
     if( rx==SQLITE_OK && res==0 ){
       rc = sqliteBtreeDelete(pCrsr);
     }
     assert( p->aCsr[i].deferredMoveto==0 );
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -3512,22 +3494,25 @@ case OP_IdxDelete: {
 */
 case OP_IdxRecno: {
   int i = pOp->p1;
-  int tos = ++p->tos;
   BtCursor *pCrsr;
 
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+  assert( i>=0 && i<p->nCursor );
+  pTos++;
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int v;
     int sz;
     assert( p->aCsr[i].deferredMoveto==0 );
     sqliteBtreeKeySize(pCrsr, &sz);
     if( sz<sizeof(u32) ){
-      aStack[tos].flags = MEM_Null;
+      pTos->flags = MEM_Null;
     }else{
       sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
       v = keyToInt(v);
-      aStack[tos].i = v;
-      aStack[tos].flags = MEM_Int;
+      pTos->i = v;
+      pTos->flags = MEM_Int;
     }
+  }else{
+    pTos->flags = MEM_Null;
   }
   break;
 }
@@ -3561,15 +3546,16 @@ case OP_IdxLT:
 case OP_IdxGT:
 case OP_IdxGE: {
   int i= pOp->p1;
-  int tos = p->tos;
   BtCursor *pCrsr;
 
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+  assert( i>=0 && i<p->nCursor );
+  assert( pTos>=p->aStack );
+  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int res, rc;
  
-    Stringify(p, tos);
+    Stringify(pTos);
     assert( p->aCsr[i].deferredMoveto==0 );
-    rc = sqliteBtreeKeyCompare(pCrsr, aStack[tos].z, aStack[tos].n, 4, &res);
+    rc = sqliteBtreeKeyCompare(pCrsr, pTos->z, pTos->n, 4, &res);
     if( rc!=SQLITE_OK ){
       break;
     }
@@ -3582,7 +3568,8 @@ case OP_IdxGE: {
       pc = pOp->p2 - 1 ;
     }
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -3597,14 +3584,13 @@ case OP_IdxGE: {
 */
 case OP_IdxIsNull: {
   int i = pOp->p1;
-  int tos = p->tos;
   int k, n;
   const char *z;
 
-  assert( tos>=0 );
-  assert( aStack[tos].flags & MEM_Str );
-  z = aStack[tos].z;
-  n = aStack[tos].n;
+  assert( pTos>=p->aStack );
+  assert( pTos->flags & MEM_Str );
+  z = pTos->z;
+  n = pTos->n;
   for(k=0; k<n && i>0; i--){
     if( z[k]=='a' ){
       pc = pOp->p2-1;
@@ -3613,7 +3599,8 @@ case OP_IdxIsNull: {
     while( k<n && z[k] ){ k++; }
     k++;
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -3677,7 +3664,6 @@ case OP_Clear: {
 */
 case OP_CreateIndex:
 case OP_CreateTable: {
-  int i = ++p->tos;
   int pgno;
   assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
   assert( pOp->p2>=0 && pOp->p2<db->nDb );
@@ -3687,9 +3673,10 @@ case OP_CreateTable: {
   }else{
     rc = sqliteBtreeCreateIndex(db->aDb[pOp->p2].pBt, &pgno);
   }
+  pTos++;
   if( rc==SQLITE_OK ){
-    aStack[i].i = pgno;
-    aStack[i].flags = MEM_Int;
+    pTos->i = pgno;
+    pTos->flags = MEM_Int;
     *(u32*)pOp->p3 = pgno;
     pOp->p3 = 0;
   }
@@ -3715,14 +3702,14 @@ case OP_CreateTable: {
 case OP_IntegrityCk: {
   int nRoot;
   int *aRoot;
-  int tos = ++p->tos;
   int iSet = pOp->p1;
   Set *pSet;
   int j;
   HashElem *i;
   char *z;
 
-  VERIFY( if( iSet<0 || iSet>=p->nSet ) goto bad_instruction; )
+  assert( iSet>=0 && iSet<p->nSet );
+  pTos++;
   pSet = &p->aSet[iSet];
   nRoot = sqliteHashCount(&pSet->hash);
   aRoot = sqliteMallocRaw( sizeof(int)*(nRoot+1) );
@@ -3736,13 +3723,13 @@ case OP_IntegrityCk: {
   z = sqliteBtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
   if( z==0 || z[0]==0 ){
     if( z ) sqliteFree(z);
-    aStack[tos].z = "ok";
-    aStack[tos].n = 3;
-    aStack[tos].flags = MEM_Str | MEM_Static;
+    pTos->z = "ok";
+    pTos->n = 3;
+    pTos->flags = MEM_Str | MEM_Static;
   }else{
-    aStack[tos].z = z;
-    aStack[tos].n = strlen(z) + 1;
-    aStack[tos].flags = MEM_Str | MEM_Dyn;
+    pTos->z = z;
+    pTos->n = strlen(z) + 1;
+    pTos->flags = MEM_Str | MEM_Dyn;
   }
   sqliteFree(aRoot);
   break;
@@ -3755,7 +3742,7 @@ case OP_IntegrityCk: {
 */
 case OP_ListWrite: {
   Keylist *pKeylist;
-  VERIFY( if( p->tos<0 ) goto not_enough_stack; )
+  assert( pTos>=p->aStack );
   pKeylist = p->pList;
   if( pKeylist==0 || pKeylist->nUsed>=pKeylist->nKey ){
     pKeylist = sqliteMallocRaw( sizeof(Keylist)+999*sizeof(pKeylist->aKey[0]) );
@@ -3766,9 +3753,10 @@ case OP_ListWrite: {
     pKeylist->pNext = p->pList;
     p->pList = pKeylist;
   }
-  Integerify(p, p->tos);
-  pKeylist->aKey[pKeylist->nUsed++] = aStack[p->tos].i;
-  POPSTACK;
+  Integerify(pTos);
+  pKeylist->aKey[pKeylist->nUsed++] = pTos->i;
+  assert( pTos->flags==MEM_Int );
+  pTos--;
   break;
 }
 
@@ -3793,15 +3781,12 @@ case OP_ListRead: {
   CHECK_FOR_INTERRUPT;
   pKeylist = p->pList;
   if( pKeylist!=0 ){
-    VERIFY(
-      if( pKeylist->nRead<0 
-        || pKeylist->nRead>=pKeylist->nUsed
-        || pKeylist->nRead>=pKeylist->nKey ) goto bad_instruction;
-    )
-    p->tos++;
-    aStack[p->tos].i = pKeylist->aKey[pKeylist->nRead++];
-    aStack[p->tos].flags = MEM_Int;
-    aStack[p->tos].z = 0;
+    assert( pKeylist->nRead>=0 );
+    assert( pKeylist->nRead<pKeylist->nUsed );
+    assert( pKeylist->nRead<pKeylist->nKey );
+    pTos++;
+    pTos->i = pKeylist->aKey[pKeylist->nRead++];
+    pTos->flags = MEM_Int;
     if( pKeylist->nRead>=pKeylist->nUsed ){
       p->pList = pKeylist->pNext;
       sqliteFree(pKeylist);
@@ -3865,29 +3850,21 @@ case OP_ListPop: {
 ** made using SortMakeKey and SortMakeRec, respectively.
 */
 case OP_SortPut: {
-  int tos = p->tos;
-  int nos = tos - 1;
+  Mem *pNos = &pTos[-1];
   Sorter *pSorter;
-  VERIFY( if( tos<1 ) goto not_enough_stack; )
-  if( Dynamicify(p, tos) || Dynamicify(p, nos) ) goto no_mem;
+  assert( pNos>=p->aStack );
+  if( Dynamicify(pTos) || Dynamicify(pNos) ) goto no_mem;
   pSorter = sqliteMallocRaw( sizeof(Sorter) );
   if( pSorter==0 ) goto no_mem;
   pSorter->pNext = p->pSort;
   p->pSort = pSorter;
-  assert( aStack[tos].flags & MEM_Dyn );
-  pSorter->nKey = aStack[tos].n;
-  pSorter->zKey = aStack[tos].z;
-  pSorter->nData = aStack[nos].n;
-  if( aStack[nos].flags & MEM_Dyn ){
-    pSorter->pData = aStack[nos].z;
-  }else{
-    pSorter->pData = sqliteStrDup(aStack[nos].z);
-  }
-  aStack[tos].flags = 0;
-  aStack[nos].flags = 0;
-  aStack[tos].z = 0;
-  aStack[nos].z = 0;
-  p->tos -= 2;
+  assert( pTos->flags & MEM_Dyn );
+  pSorter->nKey = pTos->n;
+  pSorter->zKey = pTos->z;
+  assert( pNos->flags & MEM_Dyn );
+  pSorter->nData = pNos->n;
+  pSorter->pData = pNos->z;
+  pTos -= 2;
   break;
 }
 
@@ -3902,35 +3879,37 @@ case OP_SortMakeRec: {
   char **azArg;
   int nByte;
   int nField;
-  int i, j;
+  int i;
+  Mem *pRec;
 
   nField = pOp->p1;
-  VERIFY( if( p->tos+1<nField ) goto not_enough_stack; )
+  pRec = &pTos[1-nField];
+  assert( pRec>=p->aStack );
   nByte = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( (aStack[i].flags & MEM_Null)==0 ){
-      Stringify(p, i);
-      nByte += aStack[i].n;
+  for(i=0; i<nField; i++, pRec++){
+    if( (pRec->flags & MEM_Null)==0 ){
+      Stringify(pRec);
+      nByte += pRec->n;
     }
   }
   nByte += sizeof(char*)*(nField+1);
   azArg = sqliteMallocRaw( nByte );
   if( azArg==0 ) goto no_mem;
   z = (char*)&azArg[nField+1];
-  for(j=0, i=p->tos-nField+1; i<=p->tos; i++, j++){
-    if( aStack[i].flags & MEM_Null ){
-      azArg[j] = 0;
+  for(pRec=&pTos[1-nField], i=0; i<nField; i++, pRec++){
+    if( pRec->flags & MEM_Null ){
+      azArg[i] = 0;
     }else{
-      azArg[j] = z;
-      strcpy(z, aStack[i].z);
-      z += aStack[i].n;
+      azArg[i] = z;
+      memcpy(z, pRec->z, pRec->n);
+      z += pRec->n;
     }
   }
-  sqliteVdbePopStack(p, nField);
-  p->tos++;
-  aStack[p->tos].n = nByte;
-  aStack[p->tos].z = (char*)azArg;
-  aStack[p->tos].flags = MEM_Str|MEM_Dyn;
+  popStack(&pTos, nField);
+  pTos++;
+  pTos->n = nByte;
+  pTos->z = (char*)azArg;
+  pTos->flags = MEM_Str | MEM_Dyn;
   break;
 }
 
@@ -3954,41 +3933,42 @@ case OP_SortMakeKey: {
   int nByte;
   int nField;
   int i, j, k;
+  Mem *pRec;
 
   nField = strlen(pOp->p3);
-  VERIFY( if( p->tos+1<nField ) goto not_enough_stack; )
+  pRec = &pTos[1-nField];
   nByte = 1;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( (aStack[i].flags & MEM_Null)!=0 ){
+  for(i=0; i<nField; i++, pRec++){
+    if( pRec->flags & MEM_Null ){
       nByte += 2;
     }else{
-      Stringify(p, i);
-      nByte += aStack[i].n+2;
+      Stringify(pRec);
+      nByte += pRec->n+2;
     }
   }
   zNewKey = sqliteMallocRaw( nByte );
   if( zNewKey==0 ) goto no_mem;
   j = 0;
   k = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( (aStack[i].flags & MEM_Null)!=0 ){
+  for(pRec=&pTos[1-nField], i=0; i<nField; i++, pRec++){
+    if( pRec->flags & MEM_Null ){
       zNewKey[j++] = 'N';
       zNewKey[j++] = 0;
       k++;
     }else{
       zNewKey[j++] = pOp->p3[k++];
-      memcpy(&zNewKey[j], aStack[i].z, aStack[i].n-1);
-      j += aStack[i].n-1;
+      memcpy(&zNewKey[j], pRec->z, pRec->n-1);
+      j += pRec->n-1;
       zNewKey[j++] = 0;
     }
   }
   zNewKey[j] = 0;
   assert( j<nByte );
-  sqliteVdbePopStack(p, nField);
-  p->tos++;
-  aStack[p->tos].n = nByte;
-  aStack[p->tos].flags = MEM_Str|MEM_Dyn;
-  aStack[p->tos].z = zNewKey;
+  popStack(&pTos, nField);
+  pTos++;
+  pTos->n = nByte;
+  pTos->flags = MEM_Str|MEM_Dyn;
+  pTos->z = zNewKey;
   break;
 }
 
@@ -4041,10 +4021,10 @@ case OP_SortNext: {
   CHECK_FOR_INTERRUPT;
   if( pSorter!=0 ){
     p->pSort = pSorter->pNext;
-    p->tos++;
-    aStack[p->tos].z = pSorter->pData;
-    aStack[p->tos].n = pSorter->nData;
-    aStack[p->tos].flags = MEM_Str|MEM_Dyn;
+    pTos++;
+    pTos->z = pSorter->pData;
+    pTos->n = pSorter->nData;
+    pTos->flags = MEM_Str|MEM_Dyn;
     sqliteFree(pSorter->zKey);
     sqliteFree(pSorter);
   }else{
@@ -4061,23 +4041,25 @@ case OP_SortNext: {
 ** callback on it.
 */
 case OP_SortCallback: {
-  int i = p->tos;
-  VERIFY( if( i<0 ) goto not_enough_stack; )
+  assert( pTos>=p->aStack );
+  assert( pTos->flags & MEM_Str );
   if( p->xCallback==0 ){
     p->pc = pc+1;
-    p->azResColumn = (char**)aStack[i].z;
+    p->azResColumn = (char**)pTos->z;
     p->nResColumn = pOp->p1;
     p->popStack = 1;
+    p->pTos = pTos;
     return SQLITE_ROW;
   }else{
     if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
-    if( p->xCallback(p->pCbArg, pOp->p1, (char**)aStack[i].z, p->azColName)!=0){
+    if( p->xCallback(p->pCbArg, pOp->p1, (char**)pTos->z, p->azColName)!=0){
       rc = SQLITE_ABORT;
     }
     if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
     p->nCallback++;
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   if( sqlite_malloc_failed ) goto no_mem;
   break;
 }
@@ -4097,7 +4079,7 @@ case OP_SortReset: {
 ** If P3 is "stdin" then open standard input for reading.
 */
 case OP_FileOpen: {
-  VERIFY( if( pOp->p3==0 ) goto bad_instruction; )
+  assert( pOp->p3!=0 );
   if( p->pFile ){
     if( p->pFile!=stdin ) fclose(p->pFile);
     p->pFile = 0;
@@ -4242,20 +4224,19 @@ fileread_jump:
 case OP_FileColumn: {
   int i = pOp->p1;
   char *z;
-  if( VERIFY( i>=0 && i<p->nField && ) p->azField ){
+  assert( i>=0 && i<p->nField );
+  if( p->azField ){
     z = p->azField[i];
   }else{
     z = 0;
   }
-  p->tos++;
+  pTos++;
   if( z ){
-    aStack[p->tos].n = strlen(z) + 1;
-    aStack[p->tos].z = z;
-    aStack[p->tos].flags = MEM_Str;
+    pTos->n = strlen(z) + 1;
+    pTos->z = z;
+    pTos->flags = MEM_Str | MEM_Ephem;
   }else{
-    aStack[p->tos].n = 0;
-    aStack[p->tos].z = 0;
-    aStack[p->tos].flags = MEM_Null;
+    pTos->flags = MEM_Null;
   }
   break;
 }
@@ -4272,11 +4253,10 @@ case OP_FileColumn: {
 */
 case OP_MemStore: {
   int i = pOp->p1;
-  int tos = p->tos;
   char *zOld;
   Mem *pMem;
   int flags;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
+  assert( pTos>=p->aStack );
   if( i>=p->nMem ){
     int nOld = p->nMem;
     Mem *aMem;
@@ -4286,7 +4266,7 @@ case OP_MemStore: {
     if( aMem!=p->aMem ){
       int j;
       for(j=0; j<nOld; j++){
-        if( aMem[j].z==p->aMem[j].zShort ){
+        if( aMem[j].flags & MEM_Short ){
           aMem[j].z = aMem[j].zShort;
         }
       }
@@ -4303,26 +4283,24 @@ case OP_MemStore: {
   }else{
     zOld = 0;
   }
-  *pMem = aStack[tos];
+  *pMem = *pTos;
   flags = pMem->flags;
-  if( flags & (MEM_Static|MEM_Dyn|MEM_Ephem) ){
-    if( (flags & MEM_Static)!=0 || (pOp->p2 && (flags & MEM_Dyn)!=0) ){
-      /* pMem->z = zStack[tos]; *** do nothing */
-    }else if( flags & MEM_Str ){
+  if( flags & MEM_Dyn ){
+    if( pOp->p2 ){
+      pTos->flags = MEM_Null;
+    }else{
+      /* OR: perhaps just make the stack ephermeral */
       pMem->z = sqliteMallocRaw( pMem->n );
       if( pMem->z==0 ) goto no_mem;
-      memcpy(pMem->z, aStack[tos].z, pMem->n);
-      pMem->flags |= MEM_Dyn;
-      pMem->flags &= ~(MEM_Static|MEM_Ephem);
+      memcpy(pMem->z, pTos->z, pMem->n);
     }
-  }else{
+  }else if( flags & MEM_Short ){
     pMem->z = pMem->zShort;
   }
   if( zOld ) sqliteFree(zOld);
   if( pOp->p2 ){
-    aStack[tos].z = 0;
-    aStack[tos].flags = 0;
-    POPSTACK;
+    Release(pTos);
+    pTos--;
   }
   break;
 }
@@ -4337,14 +4315,13 @@ case OP_MemStore: {
 ** value pushed onto the stack will change too.
 */
 case OP_MemLoad: {
-  int tos = ++p->tos;
   int i = pOp->p1;
-  VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; )
-  memcpy(&aStack[tos], &p->aMem[i], sizeof(aStack[tos])-NBFS);;
-  if( aStack[tos].flags & MEM_Str ){
-    /* aStack[tos].z = p->aMem[i].z; */
-    aStack[tos].flags |= MEM_Ephem;
-    aStack[tos].flags &= ~(MEM_Dyn|MEM_Static);
+  assert( i>=0 && i<p->nMem );
+  pTos++;
+  memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);;
+  if( pTos->flags & MEM_Str ){
+    pTos->flags |= MEM_Ephem;
+    pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
   }
   break;
 }
@@ -4361,9 +4338,9 @@ case OP_MemLoad: {
 case OP_MemIncr: {
   int i = pOp->p1;
   Mem *pMem;
-  VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; )
+  assert( i>=0 && i<p->nMem );
   pMem = &p->aMem[i];
-  VERIFY( if( pMem->flags != MEM_Int ) goto bad_instruction; )
+  assert( pMem->flags==MEM_Int );
   pMem->i++;
   if( pOp->p2>0 && pMem->i>0 ){
      pc = pOp->p2 - 1;
@@ -4392,7 +4369,7 @@ case OP_AggReset: {
 */
 case OP_AggInit: {
   int i = pOp->p2;
-  VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
+  assert( i>=0 && i<p->agg.nMem );
   p->agg.apFunc[i] = (FuncDef*)pOp->p3;
   break;
 }
@@ -4411,22 +4388,24 @@ case OP_AggInit: {
 case OP_AggFunc: {
   int n = pOp->p2;
   int i;
-  Mem *pMem;
+  Mem *pMem, *pRec;
+  char **azArgv = p->zArgv;
   sqlite_func ctx;
 
-  VERIFY( if( n<0 ) goto bad_instruction; )
-  VERIFY( if( p->tos+1<n ) goto not_enough_stack; )
-  VERIFY( if( aStack[p->tos].flags!=MEM_Int ) goto bad_instruction; )
-  for(i=p->tos-n; i<p->tos; i++){
-    if( aStack[i].flags & MEM_Null ){
-      aStack[i].z = 0;
+  assert( n>=0 );
+  assert( pTos->flags==MEM_Int );
+  pRec = &pTos[-n];
+  assert( pRec>=p->aStack );
+  for(i=0; i<n; i++, pRec++){
+    if( pRec->flags & MEM_Null ){
+      azArgv[i] = 0;
     }else{
-      Stringify(p, i);
+      Stringify(pRec);
+      azArgv[i] = pRec->z;
     }
-    p->zArgv[i] = aStack[i].z;
   }
-  i = aStack[p->tos].i;
-  VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
+  i = pTos->i;
+  assert( i>=0 && i<p->agg.nMem );
   ctx.pFunc = (FuncDef*)pOp->p3;
   pMem = &p->agg.pCurrent->aMem[i];
   ctx.s.z = pMem->zShort;  /* Space used for small aggregate contexts */
@@ -4434,10 +4413,10 @@ case OP_AggFunc: {
   ctx.cnt = ++pMem->i;
   ctx.isError = 0;
   ctx.isStep = 1;
-  (ctx.pFunc->xStep)(&ctx, n, (const char**)&p->zArgv[p->tos-n]);
+  (ctx.pFunc->xStep)(&ctx, n, (const char**)azArgv);
   pMem->z = ctx.pAgg;
   pMem->flags = MEM_AggCtx;
-  sqliteVdbePopStack(p, n+1);
+  popStack(&pTos, n+1);
   if( ctx.isError ){
     rc = SQLITE_ERROR;
   }
@@ -4459,15 +4438,14 @@ case OP_AggFunc: {
 ** in between an AggNext and an AggReset.
 */
 case OP_AggFocus: {
-  int tos = p->tos;
   AggElem *pElem;
   char *zKey;
   int nKey;
 
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  Stringify(p, tos);
-  zKey = aStack[tos].z; 
-  nKey = aStack[tos].n;
+  assert( pTos>=p->aStack );
+  Stringify(pTos);
+  zKey = pTos->z;
+  nKey = pTos->n;
   pElem = sqliteHashFind(&p->agg.hash, zKey, nKey);
   if( pElem ){
     p->agg.pCurrent = pElem;
@@ -4476,7 +4454,8 @@ case OP_AggFocus: {
     AggInsert(&p->agg, zKey, nKey);
     if( sqlite_malloc_failed ) goto no_mem;
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break; 
 }
 
@@ -4488,10 +4467,11 @@ case OP_AggFocus: {
 case OP_AggSet: {
   AggElem *pFocus = AggInFocus(p->agg);
   int i = pOp->p2;
-  int tos = p->tos;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
+  assert( pTos>=p->aStack );
   if( pFocus==0 ) goto no_mem;
-  if( VERIFY( i>=0 && ) i<p->agg.nMem ){
+  assert( i>=0 );
+  assert( i<p->agg.nMem );
+  if( i<p->agg.nMem ){
     Mem *pMem = &pFocus->aMem[i];
     char *zOld;
     if( pMem->flags & MEM_Dyn ){
@@ -4499,19 +4479,17 @@ case OP_AggSet: {
     }else{
       zOld = 0;
     }
-    Deephemeralize(p, tos);
-    *pMem = aStack[tos];
+    Deephemeralize(pTos);
+    *pMem = *pTos;
     if( pMem->flags & MEM_Dyn ){
-      aStack[tos].z = 0;
-      aStack[tos].flags = 0;
-    }else if( pMem->flags & (MEM_Static|MEM_AggCtx) ){
-      /* pMem->z = zStack[tos]; *** do nothing */
-    }else if( pMem->flags & MEM_Str ){
+      pTos->flags = MEM_Null;
+    }else if( pMem->flags & MEM_Short ){
       pMem->z = pMem->zShort;
     }
     if( zOld ) sqliteFree(zOld);
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -4524,13 +4502,15 @@ case OP_AggSet: {
 case OP_AggGet: {
   AggElem *pFocus = AggInFocus(p->agg);
   int i = pOp->p2;
-  int tos = ++p->tos;
   if( pFocus==0 ) goto no_mem;
-  if( VERIFY( i>=0 && ) i<p->agg.nMem ){
+  assert( i>=0 );
+  pTos++;
+  assert( i<p->agg.nMem );
+  if( i<p->agg.nMem ){
     Mem *pMem = &pFocus->aMem[i];
-    aStack[tos] = *pMem;
-    aStack[tos].flags &= ~MEM_Dyn;
-    aStack[tos].flags |= MEM_Ephem;
+    *pTos = *pMem;
+    pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
+    pTos->flags |= MEM_Ephem;
   }
   break;
 }
@@ -4578,8 +4558,7 @@ case OP_AggNext: {
         sqliteFree( aMem[i].z );
       }
       aMem[i] = ctx.s;
-      if( (aMem[i].flags & MEM_Str) &&
-              (aMem[i].flags & (MEM_Dyn|MEM_Static|MEM_Ephem))==0 ){
+      if( aMem[i].flags & MEM_Short ){
         aMem[i].z = aMem[i].zShort;
       }
     }
@@ -4608,11 +4587,11 @@ case OP_SetInsert: {
   if( pOp->p3 ){
     sqliteHashInsert(&p->aSet[i].hash, pOp->p3, strlen(pOp->p3)+1, p);
   }else{
-    int tos = p->tos;
-    if( tos<0 ) goto not_enough_stack;
-    Stringify(p, tos);
-    sqliteHashInsert(&p->aSet[i].hash, aStack[tos].z, aStack[tos].n, p);
-    POPSTACK;
+    assert( pTos>=p->aStack );
+    Stringify(pTos);
+    sqliteHashInsert(&p->aSet[i].hash, pTos->z, pTos->n, p);
+    Release(pTos);
+    pTos--;
   }
   if( sqlite_malloc_failed ) goto no_mem;
   break;
@@ -4626,14 +4605,13 @@ case OP_SetInsert: {
 */
 case OP_SetFound: {
   int i = pOp->p1;
-  int tos = p->tos;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  Stringify(p, tos);
-  if( i>=0 && i<p->nSet &&
-       sqliteHashFind(&p->aSet[i].hash, aStack[tos].z, aStack[tos].n)){
+  assert( pTos>=p->aStack );
+  Stringify(pTos);
+  if( i>=0 && i<p->nSet && sqliteHashFind(&p->aSet[i].hash, pTos->z, pTos->n)){
     pc = pOp->p2 - 1;
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -4645,14 +4623,14 @@ case OP_SetFound: {
 */
 case OP_SetNotFound: {
   int i = pOp->p1;
-  int tos = p->tos;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  Stringify(p, tos);
+  assert( pTos>=p->aStack );
+  Stringify(pTos);
   if( i<0 || i>=p->nSet ||
-       sqliteHashFind(&p->aSet[i].hash, aStack[tos].z, aStack[tos].n)==0 ){
+       sqliteHashFind(&p->aSet[i].hash, pTos->z, pTos->n)==0 ){
     pc = pOp->p2 - 1;
   }
-  POPSTACK;
+  Release(pTos);
+  pTos--;
   break;
 }
 
@@ -4671,7 +4649,6 @@ case OP_SetNotFound: {
 case OP_SetFirst: 
 case OP_SetNext: {
   Set *pSet;
-  int tos;
   CHECK_FOR_INTERRUPT;
   if( pOp->p1<0 || pOp->p1>=p->nSet ){
     if( pOp->opcode==OP_SetFirst ) pc = pOp->p2 - 1;
@@ -4685,7 +4662,7 @@ case OP_SetNext: {
       break;
     }
   }else{
-    VERIFY( if( pSet->prev==0 ) goto bad_instruction; )
+    assert( pSet->prev );
     pSet->prev = sqliteHashNext(pSet->prev);
     if( pSet->prev==0 ){
       break;
@@ -4693,10 +4670,10 @@ case OP_SetNext: {
       pc = pOp->p2 - 1;
     }
   }
-  tos = ++p->tos;
-  aStack[tos].z = sqliteHashKey(pSet->prev);
-  aStack[tos].n = sqliteHashKeysize(pSet->prev);
-  aStack[tos].flags = MEM_Str | MEM_Ephem;
+  pTos++;
+  pTos->z = sqliteHashKey(pSet->prev);
+  pTos->n = sqliteHashKeysize(pSet->prev);
+  pTos->flags = MEM_Str | MEM_Ephem;
   break;
 }
 
@@ -4752,39 +4729,39 @@ default: {
       sqliteSetString(&p->zErrMsg, "jump destination out of range", (char*)0);
       rc = SQLITE_INTERNAL;
     }
-    if( p->trace && p->tos>=0 ){
+    if( p->trace && pTos>=p->aStack ){
       int i;
       fprintf(p->trace, "Stack:");
-      for(i=p->tos; i>=0 && i>p->tos-5; i--){
-        if( aStack[i].flags & MEM_Null ){
+      for(i=0; i>-5 && &pTos[i]>=p->aStack; i--){
+        if( pTos[i].flags & MEM_Null ){
           fprintf(p->trace, " NULL");
-        }else if( (aStack[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
-          fprintf(p->trace, " si:%d", aStack[i].i);
-        }else if( aStack[i].flags & MEM_Int ){
-          fprintf(p->trace, " i:%d", aStack[i].i);
-        }else if( aStack[i].flags & MEM_Real ){
-          fprintf(p->trace, " r:%g", aStack[i].r);
-        }else if( aStack[i].flags & MEM_Str ){
+        }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
+          fprintf(p->trace, " si:%d", pTos[i].i);
+        }else if( pTos[i].flags & MEM_Int ){
+          fprintf(p->trace, " i:%d", pTos[i].i);
+        }else if( pTos[i].flags & MEM_Real ){
+          fprintf(p->trace, " r:%g", pTos[i].r);
+        }else if( pTos[i].flags & MEM_Str ){
           int j, k;
           char zBuf[100];
           zBuf[0] = ' ';
-          if( aStack[i].flags & MEM_Dyn ){
+          if( pTos[i].flags & MEM_Dyn ){
             zBuf[1] = 'z';
-            assert( (aStack[i].flags & (MEM_Static|MEM_Ephem))==0 );
-          }else if( aStack[i].flags & MEM_Static ){
+            assert( (pTos[i].flags & (MEM_Static|MEM_Ephem))==0 );
+          }else if( pTos[i].flags & MEM_Static ){
             zBuf[1] = 't';
-            assert( (aStack[i].flags & (MEM_Dyn|MEM_Ephem))==0 );
-          }else if( aStack[i].flags & MEM_Ephem ){
+            assert( (pTos[i].flags & (MEM_Dyn|MEM_Ephem))==0 );
+          }else if( pTos[i].flags & MEM_Ephem ){
             zBuf[1] = 'e';
-            assert( (aStack[i].flags & (MEM_Static|MEM_Dyn))==0 );
+            assert( (pTos[i].flags & (MEM_Static|MEM_Dyn))==0 );
           }else{
             zBuf[1] = 's';
           }
           zBuf[2] = '[';
           k = 3;
-          for(j=0; j<20 && j<aStack[i].n; j++){
-            int c = aStack[i].z[j];
-            if( c==0 && j==aStack[i].n-1 ) break;
+          for(j=0; j<20 && j<pTos[i].n; j++){
+            int c = pTos[i].z[j];
+            if( c==0 && j==pTos[i].n-1 ) break;
             if( isprint(c) && !isspace(c) ){
               zBuf[k++] = c;
             }else{
@@ -4814,6 +4791,7 @@ vdbe_halt:
     rc = SQLITE_DONE;
   }
   p->magic = VDBE_MAGIC_HALT;
+  p->pTos = pTos;
   return rc;
 
   /* Jump to here if a malloc() fails.  It's hard to get a malloc()
@@ -4852,23 +4830,4 @@ abort_due_to_interrupt:
   }
   sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
   goto vdbe_halt;
-
-  /* Jump to here if a operator is encountered that requires more stack
-  ** operands than are currently available on the stack.
-  */
-not_enough_stack:
-  sqlite_snprintf(sizeof(zBuf),zBuf,"%d",pc);
-  sqliteSetString(&p->zErrMsg, "too few operands on stack at ", zBuf, (char*)0);
-  rc = SQLITE_INTERNAL;
-  goto vdbe_halt;
-
-  /* Jump here if an illegal or illformed instruction is executed.
-  */
-VERIFY(
-bad_instruction:
-  sqlite_snprintf(sizeof(zBuf),zBuf,"%d",pc);
-  sqliteSetString(&p->zErrMsg, "illegal operation at ", zBuf, (char*)0);
-  rc = SQLITE_INTERNAL;
-  goto vdbe_halt;
-)
 }
index daa25052d4eabd5a8c166c50eac34bb062a37cac..28f658a7efba6917890555f48bdb9161feeeef56 100644 (file)
@@ -129,12 +129,13 @@ typedef struct Mem Mem;
 #define MEM_Dyn       0x0010   /* Need to call sqliteFree() on Mem.z */
 #define MEM_Static    0x0020   /* Mem.z points to a static string */
 #define MEM_Ephem     0x0040   /* Mem.z points to an ephemeral string */
+#define MEM_Short     0x0080   /* Mem.z points to Mem.zShort */
 
 /* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
 ** It indicates that the corresponding AggElem.aMem.z points to a
 ** aggregate function context that needs to be finalized.
 */
-#define MEM_AggCtx    0x0040   /* Mem.z points to an agg function context */
+#define MEM_AggCtx    0x0100   /* Mem.z points to an agg function context */
 
 /*
 ** The "context" argument for a installable function.  A pointer to an
@@ -223,8 +224,8 @@ struct Vdbe {
   int nLabel;         /* Number of labels used */
   int nLabelAlloc;    /* Number of slots allocated in aLabel[] */
   int *aLabel;        /* Space to hold the labels */
-  int tos;            /* Index of top of stack */
   Mem *aStack;        /* The operand stack, except string values */
+  Mem *pTos;          /* Top entry in the operand stack */
   char **zArgv;       /* Text values used by the callback */
   char **azColName;   /* Becomes the 4th parameter to callbacks */
   int nCursor;        /* Number of slots in aCsr[] */
@@ -274,16 +275,6 @@ struct Vdbe {
 #define VDBE_MAGIC_HALT     0x519c2973    /* VDBE has completed execution */
 #define VDBE_MAGIC_DEAD     0xb606c3c8    /* The VDBE has been deallocated */
 
-/*
-** Here is a macro to handle the common case of popping the stack
-** once.  This macro only works from within the sqliteVdbeExec()
-** function.
-*/
-#define POPSTACK \
-  assert(p->tos>=0); \
-  if( aStack[p->tos].flags & MEM_Dyn ) sqliteFree(aStack[p->tos].z); \
-  p->tos--;
-
 /*
 ** Function prototypes
 */
index 3648062e0b439d54554fd72df799bbde319fe02f..f3f73cad00845cab3fabba01a1077f35fd0b1b0c 100644 (file)
@@ -388,7 +388,7 @@ char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){
     if( n<NBFS-1 ){
       memcpy(p->s.zShort, zResult, n);
       p->s.zShort[n] = 0;
-      p->s.flags = MEM_Str;
+      p->s.flags = MEM_Str | MEM_Short;
       p->s.z = p->s.zShort;
     }else{
       p->s.z = sqliteMallocRaw( n+1 );
@@ -597,8 +597,8 @@ void sqliteVdbeMakeReady(
     assert( nVar>=0 );
     n = isExplain ? 10 : p->nOp;
     p->aStack = sqliteMalloc(
-    n*(sizeof(p->aStack[0]) + 2*sizeof(char*))     /* aStack and zArgv */
-      + p->nVar*(sizeof(char*)+sizeof(int)+1)      /* azVar, anVar, abVar */
+      n*(sizeof(p->aStack[0]) + 2*sizeof(char*))     /* aStack and zArgv */
+        + p->nVar*(sizeof(char*)+sizeof(int)+1)    /* azVar, anVar, abVar */
     );
     p->zArgv = (char**)&p->aStack[n];
     p->azColName = (char**)&p->zArgv[n];
@@ -614,7 +614,7 @@ void sqliteVdbeMakeReady(
     p->trace = stdout;
   }
 #endif
-  p->tos = -1;
+  p->pTos = &p->aStack[-1];
   p->pc = 0;
   p->rc = SQLITE_OK;
   p->uniqueCnt = 0;
@@ -651,22 +651,6 @@ void sqliteVdbeSorterReset(Vdbe *p){
   }
 }
 
-/*
-** Pop the stack N times.  Free any memory associated with the
-** popped stack elements.
-*/
-void sqliteVdbePopStack(Vdbe *p, int N){
-  assert( N>=0 );
-  if( p->aStack==0 ) return;
-  while( N-- > 0 ){
-    if( p->aStack[p->tos].flags & MEM_Dyn ){
-      sqliteFree(p->aStack[p->tos].z);
-    }
-    p->aStack[p->tos].flags = 0;
-    p->tos--;
-  }
-}
-
 /*
 ** Reset an Agg structure.  Delete all its contents. 
 **
@@ -758,7 +742,16 @@ static void closeAllCursors(Vdbe *p){
 */
 static void Cleanup(Vdbe *p){
   int i;
-  sqliteVdbePopStack(p, p->tos+1);
+  if( p->aStack ){
+    Mem *pTos = p->pTos;
+    while( pTos>=p->aStack ){
+      if( pTos->flags & MEM_Dyn ){
+        sqliteFree(pTos->z);
+      }
+      pTos--;
+    }
+    p->pTos = pTos;
+  }
   closeAllCursors(p);
   if( p->aMem ){
     for(i=0; i<p->nMem; i++){
@@ -871,7 +864,7 @@ int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){
       db->aDb[i].inTrans = 1;
     }
   }
-  assert( p->tos<p->pc || sqlite_malloc_failed==1 );
+  assert( p->pTos<&p->aStack[p->pc] || sqlite_malloc_failed==1 );
 #ifdef VDBE_PROFILE
   {
     FILE *out = fopen("vdbe_profile.out", "a");
index bf12cb406b9565a2b3e98299d84d8f1d2d276dbc..185f1748971b6c91eab4095b3758501a82fa1241 100644 (file)
@@ -10,6 +10,9 @@
   mem[$10] = $0
 }
 /[0-9]+ free / {
+  if (mem[$6]=="") {
+    print "*** free without a malloc at",$6
+  }
   mem[$6] = "";
   str[$6] = ""
 }