Replace the NOPUSH_MASKs with a bit-vector mechanism that can contain

several different properties about each opcode. (CVS 4677)

FossilOrigin-Name: 042dcb9621934d0318a7c6e9cd08b20a569db367
This commit is contained in:
drh 2008-01-04 16:50:09 +00:00
parent dd2fb29be8
commit 3a40f696d4
6 changed files with 144 additions and 132 deletions

View File

@ -1,5 +1,5 @@
C Modify\sFifoRead\sand\sFifoWrite\sto\swork\sexclusively\swith\smemory\scells.\s(CVS\s4676)
D 2008-01-04T13:57:26
C Replace\sthe\sNOPUSH_MASKs\swith\sa\sbit-vector\smechanism\sthat\scan\scontain\nseveral\sdifferent\sproperties\sabout\seach\sopcode.\s(CVS\s4677)
D 2008-01-04T16:50:09
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -69,7 +69,7 @@ F mkdll.sh 5f8438dcac98e795d7df6529159a1ec566de0183
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb
F mkopcodec.awk 3fb9bf077053c968451f4dd03d11661ac373f9d1
F mkopcodeh.awk 799a299eaf3173c0f8ac0bd7c4b49c0f4d4590ca
F mkopcodeh.awk 1ae5b01fef9105aa04c3b943223b80ad116e7161
F mkso.sh 24bde4c09e6fe80f718db3c31c068f45e13a2f2c
F publish.sh 1c0658c63d70f182a8f5e17cc28422f1b237f51d
F publish_osx.sh eca87df1e3d43d128d97d3261fd48b3d6877996e
@ -168,11 +168,11 @@ F src/update.c eaacf59269bd076adca6fab6f5d16ce53419380b
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
F src/vdbe.c c562e01b491b589f6e0f830bec7ab1507d1ac844
F src/vdbe.c 8e42b5ce4d69ecf2d17bffd8e520343324785d3e
F src/vdbe.h bb128757b84280504a1243c450fd13ead248ede5
F src/vdbeInt.h 869d0f550354c1364dde1d3611d770bd1c767505
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
F src/vdbeaux.c eaf5bef96a4564eb0a9b473aa8628b3b5889839d
F src/vdbeaux.c 02fef605e37abe4bcec3dbfa42925aac638e5e2b
F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
@ -603,7 +603,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 173f281334d340290e1978abea5d1ea804141910
R 94a66c73f79f80d8b0a98041731b34af
U danielk1977
Z fb5d354c01f2e7900c511aa6a77f6954
P 2c913908a47e7ace7d964067e3566d232ee2d494
R 7c9e5a234b0556d1a08e9283ee39d755
U drh
Z 240c930bb8f98d16c4e85e184409b234

View File

@ -1 +1 @@
2c913908a47e7ace7d964067e3566d232ee2d494
042dcb9621934d0318a7c6e9cd08b20a569db367

View File

@ -50,6 +50,13 @@
sub(/:/,"",name)
sub("\r","",name)
op[name] = -1
out1[name] = 0
out2[name] = 0
out3[name] = 0
jump[name] = 0
in1[name] = 0
in2[name] = 0
in3[name] = 0
for(i=3; i<NF; i++){
if($i=="same" && $(i+1)=="as"){
sym = $(i+2)
@ -58,8 +65,23 @@
used[op[name]] = 1
sameas[op[name]] = sym
}
sub(",","",$i)
if($i=="no-push"){
nopush[name] = 1
}else if($i=="out1"){
out1[name] = 1
}else if($i=="out2"){
out2[name] = 2
}else if($i=="out3"){
out3[name] = 3
}else if($i=="in1"){
in1[name] = 1
}else if($i=="in2"){
in2[name] = 1
}else if($i=="in3"){
in3[name] = 1
}else if($i=="jump"){
jump[name] = 1
}
}
}
@ -96,32 +118,46 @@ END {
}
}
# Generate the 10 16-bit bitmasks used by function opcodeUsesStack()
# in vdbeaux.c. See comments in that function for details.
#
nopush[0] = 0 # 0..15
nopush[1] = 0 # 16..31
nopush[2] = 0 # 32..47
nopush[3] = 0 # 48..63
nopush[4] = 0 # 64..79
nopush[5] = 0 # 80..95
nopush[6] = 0 # 96..111
nopush[7] = 0 # 112..127
nopush[8] = 0 # 128..143
nopush[9] = 0 # 144..159
# Generate the bitvectors:
#
# bit 0: jump
# bit 1: output on P1
# bit 2: output on P2
# bit 3: output on P3
# bit 4: input on P1
# bit 5: input on P2
# bit 6: input on P3
# bit 7: pushes a result onto stack
#
for(i=0; i<=max; i++) bv[i] = 0;
for(name in op){
if( nopush[name] ){
n = op[name]
j = n%16
i = ((n - j)/16)
nopush[i] = nopush[i] + (2^j)
}
x = op[name]
if( jump[name] ) bv[x] += 0x01;
if( out1[name] ) bv[x] += 0x02;
if( out2[name] ) bv[x] += 0x04;
if( out3[name] ) bv[x] += 0x08;
if( in1[name] ) bv[x] += 0x10;
if( in2[name] ) bv[x] += 0x20;
if( in3[name] ) bv[x] += 0x40;
if( !nopush[name] ) bv[x] += 0x80;
}
printf "\n"
print "/* Opcodes that are guaranteed to never push a value onto the stack"
print "** contain a 1 their corresponding position of the following mask"
print "** set. See the opcodeNoPush() function in vdbeaux.c */"
for(i=0; i<10; i++){
printf "#define NOPUSH_MASK_%d 0x%04x\n", i, nopush[i]
print "\n"
print "/* Properties such as \"out2\" or \"jump\" that are specified in"
print "** comments following the "case" for each opcode in the vdbe.c"
print "** are encoded into bitvectors as follows:"
print "*/"
print "#define OPFLG_JUMP 0x01 /* jump: P2 holds a jump target */"
print "#define OPFLG_OUT1 0x02 /* out1: P1 specifies output reg */"
print "#define OPFLG_OUT2 0x04 /* out2: P2 specifies output reg */"
print "#define OPFLG_OUT3 0x08 /* out3: P3 specifies output reg */"
print "#define OPFLG_IN1 0x10 /* in1: P1 is an input reg */"
print "#define OPFLG_IN2 0x20 /* in2: P2 is an input reg */"
print "#define OPFLG_IN3 0x40 /* in3: P3 is an input reg */"
print "#define OPFLG_PUSH 0x80 /* omits no-push: Does not push */"
print "#define OPFLG_INITIALIZER {\\"
for(i=0; i<=max; i++){
printf " 0x%02x,", bv[i]
if( i%10==9 ) printf("\\\n");
}
print "}"
}

View 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.676 2008/01/04 13:57:26 danielk1977 Exp $
** $Id: vdbe.c,v 1.677 2008/01/04 16:50:09 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -172,6 +172,31 @@ static void _storeTypeInfo(Mem *pMem){
}
}
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
** created by mkopcodeh.awk during compilation. Data is obtained
** from the comments following the "case OP_xxxx:" statements in
** this file.
**
** jump: OPFLG_JUMP
** out1: OPFLG_OUT1
** out2: OPFLG_OUT2
** out3: OPFLG_OUT3
** in1: OPFLG_IN1
** in2: OPFLG_IN2
** in3: OPFLG_IN3
*/
static unsigned char opcodeProperty[] = OPFLG_INITIALIZER;
/*
** Return true if an opcode has any of the OPFLG_xxx properties
** specified by mask.
*/
int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
assert( opcode>0 && opcode<sizeof(opcodeProperty) );
return (opcodeProperty[opcode]&mask)!=0;
}
/*
** Pop the stack N times.
*/
@ -559,18 +584,11 @@ int sqlite3VdbeExec(
#endif
#ifndef NDEBUG
/* This is to check that the return value of static function
** opcodeNoPush() (see vdbeaux.c) returns values that match the
** implementation of the virtual machine in this file. If
** opcodeNoPush() 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.
/* This is to check to make sure that the OPFLG_PUSH property
** is set correctly on all opcodes.
*/
pStackLimit = pTos;
if( !sqlite3VdbeOpcodeNoPush(pOp->opcode) ){
if( sqlite3VdbeOpcodeHasProperty(pOp->opcode, OPFLG_PUSH) ){
pStackLimit++;
}
#endif
@ -619,7 +637,7 @@ int sqlite3VdbeExec(
** the one at index P2 from the beginning of
** the program.
*/
case OP_Goto: { /* no-push */
case OP_Goto: { /* no-push, jump */
CHECK_FOR_INTERRUPT;
pc = pOp->p2 - 1;
break;
@ -635,7 +653,7 @@ case OP_Goto: { /* no-push */
** the return address stack will fill up and processing will abort
** with a fatal error.
*/
case OP_Gosub: { /* no-push */
case OP_Gosub: { /* no-push, jump */
assert( p->returnDepth<sizeof(p->returnStack)/sizeof(p->returnStack[0]) );
p->returnStack[p->returnDepth++] = pc+1;
pc = pOp->p2 - 1;
@ -1483,7 +1501,7 @@ case OP_AddImm: { /* no-push */
** current value if P1==0, or to the least integer that is strictly
** greater than its current value if P1==1.
*/
case OP_ForceInt: { /* no-push */
case OP_ForceInt: { /* no-push, jump */
i64 v;
assert( pTos>=p->aStack );
applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
@ -1519,7 +1537,7 @@ case OP_ForceInt: { /* no-push */
** P1 is 1, then the stack is popped. In all other cases, the depth
** of the stack is unchanged.
*/
case OP_MustBeInt: { /* no-push */
case OP_MustBeInt: { /* no-push, jump */
assert( pTos>=p->aStack );
applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
if( (pTos->flags & MEM_Int)==0 ){
@ -1724,12 +1742,12 @@ case OP_ToReal: { /* same as TK_TO_REAL, no-push */
** 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.
*/
case OP_Eq: /* same as TK_EQ, no-push */
case OP_Ne: /* same as TK_NE, no-push */
case OP_Lt: /* same as TK_LT, no-push */
case OP_Le: /* same as TK_LE, no-push */
case OP_Gt: /* same as TK_GT, no-push */
case OP_Ge: { /* same as TK_GE, no-push */
case OP_Eq: /* same as TK_EQ, no-push, jump */
case OP_Ne: /* same as TK_NE, no-push, jump */
case OP_Lt: /* same as TK_LT, no-push, jump */
case OP_Le: /* same as TK_LE, no-push, jump */
case OP_Gt: /* same as TK_GT, no-push, jump */
case OP_Ge: { /* same as TK_GE, no-push, jump */
Mem *pNos;
int flags;
int res;
@ -1957,8 +1975,8 @@ case OP_Noop: { /* no-push */
** If the value popped of the stack is NULL, then take the jump if P1
** is true and fall through if P1 is false.
*/
case OP_If: /* no-push */
case OP_IfNot: { /* no-push */
case OP_If: /* no-push, jump */
case OP_IfNot: { /* no-push, jump */
int c;
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ){
@ -1985,7 +2003,7 @@ case OP_IfNot: { /* no-push */
** pop -P1 elements from the stack only if the jump is taken and leave
** the stack unchanged if the jump is not taken.
*/
case OP_IsNull: { /* same as TK_ISNULL, no-push */
case OP_IsNull: { /* same as TK_ISNULL, no-push, jump */
if( pTos->flags & MEM_Null ){
pc = pOp->p2-1;
if( pOp->p1<0 ){
@ -2005,7 +2023,7 @@ case OP_IsNull: { /* same as TK_ISNULL, no-push */
** P1 times if P1 is greater than zero. But if P1 is negative,
** leave the stack unchanged.
*/
case OP_NotNull: { /* same as TK_NOTNULL, no-push */
case OP_NotNull: { /* same as TK_NOTNULL, no-push, jump */
int i, cnt;
cnt = pOp->p1;
if( cnt<0 ) cnt = -cnt;
@ -2346,8 +2364,8 @@ op_column_out:
*/
case OP_RegMakeRec:
case OP_RegMakeIRec:
case OP_MakeIdxRec:
case OP_MakeRecord: {
case OP_MakeIdxRec: /* jump */
case OP_MakeRecord: { /* jump */
/* Assuming the record contains N fields, the record format looks
** like this:
**
@ -3068,10 +3086,10 @@ case OP_Close: { /* no-push */
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
*/
case OP_MoveLt: /* no-push */
case OP_MoveLe: /* no-push */
case OP_MoveGe: /* no-push */
case OP_MoveGt: { /* no-push */
case OP_MoveLt: /* no-push, jump */
case OP_MoveLe: /* no-push, jump */
case OP_MoveGe: /* no-push, jump */
case OP_MoveGt: { /* no-push, jump */
int i = pOp->p1;
Cursor *pC;
@ -3201,9 +3219,9 @@ case OP_MoveGt: { /* no-push */
**
** See also: Distinct, Found, MoveTo, NotExists, IsUnique
*/
case OP_Distinct: /* no-push */
case OP_NotFound: /* no-push */
case OP_Found: { /* no-push */
case OP_Distinct: /* no-push, jump */
case OP_NotFound: /* no-push, jump */
case OP_Found: { /* no-push, jump */
int i = pOp->p1;
int alreadyExists = 0;
Cursor *pC;
@ -3260,7 +3278,7 @@ case OP_Found: { /* no-push */
**
** See also: Distinct, NotFound, NotExists, Found
*/
case OP_IsUnique: { /* no-push */
case OP_IsUnique: { /* no-push, jump */
int i = pOp->p1;
Mem *pNos = &pTos[-1];
Cursor *pCx;
@ -3360,7 +3378,7 @@ case OP_IsUnique: { /* no-push */
**
** See also: Distinct, Found, MoveTo, NotFound, IsUnique
*/
case OP_NotExists: { /* no-push */
case OP_NotExists: { /* no-push, jump */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
@ -3895,7 +3913,7 @@ case OP_NullRow: { /* no-push */
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Last: { /* no-push */
case OP_Last: { /* no-push, jump */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
@ -3931,7 +3949,7 @@ case OP_Last: { /* no-push */
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
case OP_Sort: { /* no-push */
case OP_Sort: { /* no-push, jump */
#ifdef SQLITE_TEST
sqlite3_sort_count++;
sqlite3_search_count--;
@ -3946,7 +3964,7 @@ case OP_Sort: { /* no-push */
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Rewind: { /* no-push */
case OP_Rewind: { /* no-push, jump */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
@ -3986,8 +4004,8 @@ case OP_Rewind: { /* no-push */
** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2.
*/
case OP_Prev: /* no-push */
case OP_Next: { /* no-push */
case OP_Prev: /* no-push, jump */
case OP_Next: { /* no-push, jump */
Cursor *pC;
BtCursor *pCrsr;
@ -4172,9 +4190,9 @@ case OP_IdxRowid: {
** an epsilon prior to the comparison. This makes the opcode work
** like IdxLE.
*/
case OP_IdxLT: /* no-push */
case OP_IdxGT: /* no-push */
case OP_IdxGE: { /* no-push */
case OP_IdxLT: /* no-push, jump */
case OP_IdxGT: /* no-push, jump */
case OP_IdxGE: { /* no-push, jump */
int i= pOp->p1;
Cursor *pC;
@ -4546,7 +4564,7 @@ case OP_FifoWrite: { /* no-push */
** If the Fifo is empty do not push an entry onto the stack or set
** a memory register but instead jump to P2.
*/
case OP_FifoRead: {
case OP_FifoRead: { /* jump */
i64 v;
CHECK_FOR_INTERRUPT;
if( sqlite3VdbeFifoPop(&p->sFifo, &v)==SQLITE_DONE ){
@ -4691,7 +4709,7 @@ case OP_MemIncr: { /* no-push */
** It is illegal to use this instruction on a memory cell that does
** not contain an integer. An assertion fault will result if you try.
*/
case OP_IfMemPos: { /* no-push */
case OP_IfMemPos: { /* no-push, jump */
int i = pOp->p1;
Mem *pMem;
assert( i>0 && i<=p->nMem );
@ -4710,7 +4728,7 @@ case OP_IfMemPos: { /* no-push */
** It is illegal to use this instruction on a memory cell that does
** not contain an integer. An assertion fault will result if you try.
*/
case OP_IfMemNeg: { /* no-push */
case OP_IfMemNeg: { /* no-push, jump */
int i = pOp->p1;
Mem *pMem;
assert( i>0 && i<=p->nMem );
@ -4729,7 +4747,7 @@ case OP_IfMemNeg: { /* no-push */
** It is illegal to use this instruction on a memory cell that does
** not contain an integer. An assertion fault will result if you try.
*/
case OP_IfMemZero: { /* no-push */
case OP_IfMemZero: { /* no-push, jump */
int i = pOp->p1;
Mem *pMem;
assert( i>0 && i<=p->nMem );
@ -4745,7 +4763,7 @@ case OP_IfMemZero: { /* no-push */
**
** If the value of memory cell P1 is NULL, jump to P2.
*/
case OP_IfMemNull: { /* no-push */
case OP_IfMemNull: { /* no-push, jump */
int i = pOp->p1;
assert( i>0 && i<=p->nMem );
if( p->aMem[i].flags & MEM_Null ){
@ -4900,7 +4918,7 @@ case OP_Vacuum: { /* no-push */
** the P1 database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* no-push */
case OP_IncrVacuum: { /* no-push, jump */
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
@ -5060,7 +5078,7 @@ case OP_VOpen: { /* no-push */
**
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* no-push */
case OP_VFilter: { /* no-push, jump */
int nArg;
int iQuery;
const sqlite3_module *pModule;
@ -5202,7 +5220,7 @@ case OP_VColumn: {
** jump to instruction P2. Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* no-push */
case OP_VNext: { /* no-push, jump */
const sqlite3_module *pModule;
int res = 0;

View File

@ -400,10 +400,10 @@ int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
const char *sqlite3OpcodeName(int);
int sqlite3VdbeOpcodeHasProperty(int, int);
#ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*);
int sqlite3VdbeOpcodeNoPush(u8);
#endif
int sqlite3VdbeMemTranslate(Mem*, u8);
#ifdef SQLITE_DEBUG

View File

@ -232,48 +232,6 @@ 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 opcodeNoPush(u8 op){
/* The 10 NOPUSH_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 "no-push" 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.
**
** NOPUSH_MASK_0 corresponds to opcodes 0 to 15. NOPUSH_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 const u32 masks[5] = {
NOPUSH_MASK_0 + (((unsigned)NOPUSH_MASK_1)<<16),
NOPUSH_MASK_2 + (((unsigned)NOPUSH_MASK_3)<<16),
NOPUSH_MASK_4 + (((unsigned)NOPUSH_MASK_5)<<16),
NOPUSH_MASK_6 + (((unsigned)NOPUSH_MASK_7)<<16),
NOPUSH_MASK_8 + (((unsigned)NOPUSH_MASK_9)<<16)
};
assert( op<32*5 );
return (masks[op>>5] & (1<<(op&0x1F)));
}
#ifndef NDEBUG
int sqlite3VdbeOpcodeNoPush(u8 op){
return opcodeNoPush(op);
}
#endif
/*
** Loop through the program looking for P2 values that are negative.
** Each such value is a label. Resolve the label by setting the P2
@ -338,7 +296,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
if( n>nMaxArgs ) nMaxArgs = n;
#endif
}
if( opcodeNoPush(opcode) ){
if( !sqlite3VdbeOpcodeHasProperty(opcode, OPFLG_PUSH) ){
nMaxStack--;
}