From 7cc84c2cdd5acb3331b27298613ca5e653741099 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 11 Apr 2016 13:36:42 +0000 Subject: [PATCH] Remove the VdbeOp.opflags field and its associated initialization overhead. Update mkopcodeh.tcl to reorder opcode numbers to help the resolveP2Values() routine run faster. FossilOrigin-Name: 099478fa7521ba52262ef2bf24dd8f0114ce92e1 --- manifest | 20 ++++---- manifest.uuid | 2 +- src/parse.y | 45 +++++++++--------- src/vdbe.c | 69 ++++++++++++++------------- src/vdbe.h | 2 +- src/vdbeaux.c | 113 +++++++++++++++++++++++++-------------------- tool/mkopcodeh.tcl | 35 ++++++++++++-- 7 files changed, 165 insertions(+), 121 deletions(-) diff --git a/manifest b/manifest index feae043873..ce95096bc7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Back\soff\sof\sthe\sparser\soptimization\sin\sthe\sprevious\scheck-in,\sslightly,\sto\npreserve\ssome\sbackwards\scompatibility\sregarding\ssome\sundocumented\sbehavior\nin\sthe\s'#AAA'\sstyle\squery\sparameter. -D 2016-04-11T01:43:33.203 +C Remove\sthe\sVdbeOp.opflags\sfield\sand\sits\sassociated\sinitialization\soverhead.\nUpdate\smkopcodeh.tcl\sto\sreorder\sopcode\snumbers\sto\shelp\sthe\sresolveP2Values()\nroutine\srun\sfaster. +D 2016-04-11T13:36:42.250 F Makefile.in eba680121821b8a60940a81454316f47a341487a F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 1f123a0757f6f04f0341accb46457e116817159a @@ -364,7 +364,7 @@ F src/os_win.c b3ba9573d8d893e70a6a8015bbee572ecf7ffbef F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c 38718a019ca762ba4f6795425d5a54db70d1790d F src/pager.h e1d38a2f14849e219df0f91f8323504d134c8a56 -F src/parse.y 52cdeb4f37634d0ccd2998aab099b7bbb690b0d3 +F src/parse.y 10eb2f3fb62341291528c7984498054731f9d31e F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545 F src/pcache1.c c40cdb93586e21b5dd826b5e671240bd91c26b05 @@ -441,11 +441,11 @@ F src/update.c 3e67ab3c0814635f355fb1f8ab010a2b9e016e7d F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c 19509465217b673b38d5804a72778908b138953f F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52 -F src/vdbe.c e16e8625829858b2bf343c3cdd72bb43eab7d643 -F src/vdbe.h c16ba943d407baa1c7085eefea73a063fc631863 +F src/vdbe.c d3843a66d74a7696477ee5141e5eb9a7e5e2401c +F src/vdbe.h 5591b5add447096e31288b5a0a78ec5d7b5c5170 F src/vdbeInt.h ddb157974436d87652de7dc641f7191496d9a8cd F src/vdbeapi.c ba85b78fe08dc4a9ce747e62c89a2b4a4547e74c -F src/vdbeaux.c 749b2a346cd2eba483e05825553406da1065d03e +F src/vdbeaux.c b0bd706639fda1ee3aa786b3a01a798e13e811d4 F src/vdbeblob.c c9f2f494b911c6fa34efd9803f0a10807da80f77 F src/vdbemem.c 5cfef60e60e19cab6275d1b975bf4c791d575beb F src/vdbesort.c 307460bfa4de4d1c3901fcd42089159131e34062 @@ -1420,7 +1420,7 @@ F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7 F tool/mkkeywordhash.c f7f3b342211ac6a14258b9726d5b97cf4f548f22 F tool/mkmsvcmin.tcl 2f12f7fa8858bbe61cf81820a2da96c79ed1ca8d F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c -F tool/mkopcodeh.tcl 385c62d78c38b2d92146dcb5abd319dbbc33506d +F tool/mkopcodeh.tcl 3b1ee0fd2452b0e2c0381956269a9ac3788255a3 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkpragmatab.tcl f0d5bb266d1d388cf86fce5ba01a891e95d72d41 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1482,7 +1482,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 16df71284bf081c8b3d3aa57c129a07067ddbed3 -R 667818294699cc99ee5b525ba6ac6436 +P ef1966c2469a0f5dbdb31a0287bd37badb2b8f28 +R 39896b563a0174d278e56658538b5996 U drh -Z c1e211272b38ff3536c2cdaeb19c42fc +Z 4b0063de72cbcb5b307015ce248a50de diff --git a/manifest.uuid b/manifest.uuid index 01abafd845..9a8e083986 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef1966c2469a0f5dbdb31a0287bd37badb2b8f28 \ No newline at end of file +099478fa7521ba52262ef2bf24dd8f0114ce92e1 \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index 605751fd9e..ae763e46d6 100644 --- a/src/parse.y +++ b/src/parse.y @@ -194,28 +194,6 @@ columnlist ::= columnlist COMMA columnname carglist. columnlist ::= columnname carglist. columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);} -// An IDENTIFIER can be a generic identifier, or one of several -// keywords. Any non-standard keyword can also be an identifier. -// -%token_class id ID|INDEXED. - -// The following directive causes tokens ABORT, AFTER, ASC, etc. to -// fallback to ID if they will not parse as their original value. -// This obviates the need for the "id" nonterminal. -// -%fallback ID - ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW - CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR - IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN - QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW - ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT -%ifdef SQLITE_OMIT_COMPOUND_SELECT - EXCEPT INTERSECT UNION -%endif SQLITE_OMIT_COMPOUND_SELECT - REINDEX RENAME CTIME_KW IF - . -%wildcard ANY. - // Define operator precedence early so that this is the first occurrence // of the operator tokens in the grammer. Keeping the operators together // causes them to be assigned integer values that are close together, @@ -240,6 +218,29 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);} %left COLLATE. %right BITNOT. +// An IDENTIFIER can be a generic identifier, or one of several +// keywords. Any non-standard keyword can also be an identifier. +// +%token_class id ID|INDEXED. + +// The following directive causes tokens ABORT, AFTER, ASC, etc. to +// fallback to ID if they will not parse as their original value. +// This obviates the need for the "id" nonterminal. +// +%fallback ID + ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW + CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR + IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN + QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW + ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT +%ifdef SQLITE_OMIT_COMPOUND_SELECT + EXCEPT INTERSECT UNION +%endif SQLITE_OMIT_COMPOUND_SELECT + REINDEX RENAME CTIME_KW IF + . +%wildcard ANY. + + // And "ids" is an identifer-or-string. // %token_class ids ID|STRING. diff --git a/src/vdbe.c b/src/vdbe.c index 593ea40806..244a4ad063 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -674,37 +674,39 @@ int sqlite3VdbeExec( /* Sanity checking on other operands */ #ifdef SQLITE_DEBUG - assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); - if( (pOp->opflags & OPFLG_IN1)!=0 ){ - assert( pOp->p1>0 ); - assert( pOp->p1<=(p->nMem+1 - p->nCursor) ); - assert( memIsValid(&aMem[pOp->p1]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); - REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); - } - if( (pOp->opflags & OPFLG_IN2)!=0 ){ - assert( pOp->p2>0 ); - assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); - assert( memIsValid(&aMem[pOp->p2]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); - REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); - } - if( (pOp->opflags & OPFLG_IN3)!=0 ){ - assert( pOp->p3>0 ); - assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); - assert( memIsValid(&aMem[pOp->p3]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); - REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); - } - if( (pOp->opflags & OPFLG_OUT2)!=0 ){ - assert( pOp->p2>0 ); - assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); - memAboutToChange(p, &aMem[pOp->p2]); - } - if( (pOp->opflags & OPFLG_OUT3)!=0 ){ - assert( pOp->p3>0 ); - assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); - memAboutToChange(p, &aMem[pOp->p3]); + { + u8 opProperty = sqlite3OpcodeProperty[pOp->opcode]; + if( (opProperty & OPFLG_IN1)!=0 ){ + assert( pOp->p1>0 ); + assert( pOp->p1<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p1]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); + REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); + } + if( (opProperty & OPFLG_IN2)!=0 ){ + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p2]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); + REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); + } + if( (opProperty & OPFLG_IN3)!=0 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p3]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); + REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); + } + if( (opProperty & OPFLG_OUT2)!=0 ){ + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + memAboutToChange(p, &aMem[pOp->p2]); + } + if( (opProperty & OPFLG_OUT3)!=0 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + memAboutToChange(p, &aMem[pOp->p3]); + } } #endif #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) @@ -6877,11 +6879,12 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ + u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode]; if( rc!=0 ) printf("rc=%d\n",rc); - if( pOrigOp->opflags & (OPFLG_OUT2) ){ + if( opProperty & (OPFLG_OUT2) ){ registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } - if( pOrigOp->opflags & OPFLG_OUT3 ){ + if( opProperty & OPFLG_OUT3 ){ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } } diff --git a/src/vdbe.h b/src/vdbe.h index ab0de8f3eb..3db32c8552 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -41,7 +41,7 @@ typedef struct SubProgram SubProgram; struct VdbeOp { u8 opcode; /* What operation to perform */ signed char p4type; /* One of the P4_xxx constants for p4 */ - u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */ + u8 notUsed1; u8 p5; /* Fifth parameter is an unsigned character */ int p1; /* First operand */ int p2; /* Second parameter (often the jump destination) */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index b3526e014a..d3f2b6b7bc 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -545,73 +545,84 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** (4) Initialize the p4.xAdvance pointer on opcodes that use it. ** ** (5) Reclaim the memory allocated for storing labels. +** +** This routine will only function correctly if the mkopcodeh.tcl generator +** script numbers the opcodes correctly. Changes to this routine must be +** coordinated with changes to mkopcodeh.tcl. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ - int i; int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; p->readOnly = 1; p->bIsReader = 0; - for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ - u8 opcode = pOp->opcode; + pOp = &p->aOp[p->nOp-1]; + while(1){ - /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing - ** cases from this switch! */ - switch( opcode ){ - case OP_Transaction: { - if( pOp->p2!=0 ) p->readOnly = 0; - /* fall thru */ - } - case OP_AutoCommit: - case OP_Savepoint: { - p->bIsReader = 1; - break; - } + /* Only JUMP opcodes and the short list of special opcodes in the switch + ** below need to be considered. The mkopcodeh.tcl generator script groups + ** all these opcodes together near the front of the opcode list. Skip + ** any opcode that does not need processing by virtual of the fact that + ** it is larger than OP_MX_JUMP, as a performance optimization. + */ + if( pOp->opcode<=OP_MX_JUMP ){ + /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing + ** cases from this switch! */ + switch( pOp->opcode ){ + case OP_Transaction: { + if( pOp->p2!=0 ) p->readOnly = 0; + /* fall thru */ + } + case OP_AutoCommit: + case OP_Savepoint: { + p->bIsReader = 1; + break; + } #ifndef SQLITE_OMIT_WAL - case OP_Checkpoint: + case OP_Checkpoint: #endif - case OP_Vacuum: - case OP_JournalMode: { - p->readOnly = 0; - p->bIsReader = 1; - break; - } + case OP_Vacuum: + case OP_JournalMode: { + p->readOnly = 0; + p->bIsReader = 1; + break; + } #ifndef SQLITE_OMIT_VIRTUALTABLE - case OP_VUpdate: { - if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; - break; - } - case OP_VFilter: { - int n; - assert( p->nOp - i >= 3 ); - assert( pOp[-1].opcode==OP_Integer ); - n = pOp[-1].p1; - if( n>nMaxArgs ) nMaxArgs = n; - break; - } + case OP_VUpdate: { + if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; + break; + } + case OP_VFilter: { + int n; + assert( (pOp - p->aOp) >= 3 ); + assert( pOp[-1].opcode==OP_Integer ); + n = pOp[-1].p1; + if( n>nMaxArgs ) nMaxArgs = n; + break; + } #endif - case OP_Next: - case OP_NextIfOpen: - case OP_SorterNext: { - pOp->p4.xAdvance = sqlite3BtreeNext; - pOp->p4type = P4_ADVANCE; - break; + case OP_Next: + case OP_NextIfOpen: + case OP_SorterNext: { + pOp->p4.xAdvance = sqlite3BtreeNext; + pOp->p4type = P4_ADVANCE; + break; + } + case OP_Prev: + case OP_PrevIfOpen: { + pOp->p4.xAdvance = sqlite3BtreePrevious; + pOp->p4type = P4_ADVANCE; + break; + } } - case OP_Prev: - case OP_PrevIfOpen: { - pOp->p4.xAdvance = sqlite3BtreePrevious; - pOp->p4type = P4_ADVANCE; - break; + if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){ + assert( ADDR(pOp->p2)nLabel ); + pOp->p2 = aLabel[ADDR(pOp->p2)]; } } - - pOp->opflags = sqlite3OpcodeProperty[opcode]; - if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ - assert( ADDR(pOp->p2)nLabel ); - pOp->p2 = aLabel[ADDR(pOp->p2)]; - } + if( pOp==p->aOp ) break; + pOp--; } sqlite3DbFree(p->db, pParse->aLabel); pParse->aLabel = 0; diff --git a/tool/mkopcodeh.tcl b/tool/mkopcodeh.tcl index 053c7f8984..c3dfc1cd4d 100644 --- a/tool/mkopcodeh.tcl +++ b/tool/mkopcodeh.tcl @@ -20,8 +20,7 @@ # during code generation, we need to generate corresponding opcodes like # OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, # code to translate from one to the other is avoided. This makes the -# code generator run (infinitesimally) faster and more importantly it makes -# the library footprint smaller. +# code generator smaller and faster. # # This script also scans for lines of the form: # @@ -159,7 +158,29 @@ for {set i 0} {$i<$nOp} {incr i} { } } -# Generate the numeric values for remaining opcodes +# Assign the next group of values to JUMP opcodes +# +for {set i 0} {$i<$nOp} {incr i} { + set name $order($i) + if {$op($name)>=0} continue + if {!$jump($name)} continue + incr cnt + while {[info exists used($cnt)]} {incr cnt} + set op($name) $cnt + set used($cnt) 1 + set def($cnt) $name +} + +# Find the numeric value for the largest JUMP opcode +# +set mxJump -1 +for {set i 0} {$i<$nOp} {incr i} { + set name $order($i) + if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)} +} + + +# Generate the numeric values for all remaining opcodes # for {set i 0} {$i<$nOp} {incr i} { set name $order($i) @@ -232,3 +253,11 @@ for {set i 0} {$i<=$max} {incr i} { } } puts "\175" +puts "" +puts "/* The sqlite3P2Values() routine is able to run faster if it knows" +puts "** the value of the largest JUMP opcode. The smaller the maximum" +puts "** JUMP opcode the better, so the mkopcodeh.tcl script that" +puts "** generated this include file strives to group all JUMP opcodes" +puts "** together near the beginning of the list." +puts "*/" +puts "#define OP_MX_JUMP $mxJump /* Maximum JUMP opcode */"