aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c12
-rw-r--r--src/vdbe.c62
-rw-r--r--src/where.c8
-rw-r--r--src/whereInt.h1
4 files changed, 48 insertions, 35 deletions
diff --git a/src/expr.c b/src/expr.c
index 4e036c934..b90d537d8 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3175,9 +3175,9 @@ void sqlite3CodeRhsOfIN(
assert( ExprUseYSub(pExpr) );
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|| pParse->nErr );
- sqlite3VdbeAddOp2(v, OP_Return, pExpr->y.sub.regReturn,
- pExpr->y.sub.iAddr);
- sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
+ sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
+ pExpr->y.sub.iAddr, 1);
+ VdbeCoverage(v);
sqlite3ClearTempRegCache(pParse);
}
}
@@ -3306,9 +3306,9 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
assert( ExprUseYSub(pExpr) );
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|| pParse->nErr );
- sqlite3VdbeAddOp2(v, OP_Return, pExpr->y.sub.regReturn,
- pExpr->y.sub.iAddr);
- sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
+ sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
+ pExpr->y.sub.iAddr, 1);
+ VdbeCoverage(v);
sqlite3ClearTempRegCache(pParse);
return rReg;
}
diff --git a/src/vdbe.c b/src/vdbe.c
index 283151d1f..ca94f0641 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -988,12 +988,17 @@ case OP_Gosub: { /* jump */
/* Opcode: Return P1 P2 P3 * *
**
-** Jump to the next instruction after the address stored in register P1.
+** Jump to the address stored in register P1. If P1 is a return address
+** register, then this accomplishes a return from a subroutine.
**
-** It used to be that after the jump, register P1 would become undefined.
-** However, for the subroutine used for the inner loop of a RIGHT JOIN,
-** it is useful for R1 register to be unchanged, so that is what happens
-** now.
+** If P3 is 1, then the jump is only taken if register P1 holds an integer
+** values, otherwise execution falls through to the next opcode, and the
+** OP_Return becomes a no-op. If P3 is 0, then register P1 must hold an
+** integer or else an assert() is raised. P3 should be set to 1 when
+** this opcode is used in combination with OP_BeginSubrtn, and set to 0
+** otherwise.
+**
+** The value in register P1 is unchanged by this opcode.
**
** P2 is not used by the byte-code engine. However, if P2 is positive
** and also less than the current address, then the "EXPLAIN" output
@@ -1002,16 +1007,15 @@ case OP_Gosub: { /* jump */
** in the subroutine from which this opcode is returnning. Thus the P2
** value is a byte-code indentation hint. See tag-20220407a in
** wherecode.c and shell.c.
-**
-** P3 is not used by the byte-code engine. However, the code generator
-** sets P3 to address of the associated OP_BeginSubrtn opcode, if there is
-** one.
*/
case OP_Return: { /* in1 */
pIn1 = &aMem[pOp->p1];
- assert( pIn1->flags==MEM_Int );
- pOp = &aOp[pIn1->u.i];
- /* pIn1->flags = MEM_Undefined; */
+ if( pIn1->flags & MEM_Int ){
+ if( pOp->p3 ) VdbeBranchTaken(1, 2);
+ pOp = &aOp[pIn1->u.i];
+ }else if( ALWAYS(pOp->p3) ){
+ VdbeBranchTaken(0, 2);
+ }
break;
}
@@ -1197,22 +1201,11 @@ case OP_Halt: {
goto vdbe_return;
}
-/* Opcode: BeginSubrtn P1 P2 * * *
-** Synopsis: r[P2]=P1
-**
-** Mark the beginning of a subroutine by loading the integer value P1
-** into register r[P2]. The P2 register is used to store the return
-** address of the subroutine call.
-**
-** This opcode is identical to OP_Integer. It has a different name
-** only to make the byte code easier to read and verify.
-*/
/* Opcode: Integer P1 P2 * * *
** Synopsis: r[P2]=P1
**
** The 32-bit integer value P1 is written into register P2.
*/
-case OP_BeginSubrtn:
case OP_Integer: { /* out2 */
pOut = out2Prerelease(p, pOp);
pOut->u.i = pOp->p1;
@@ -1319,6 +1312,28 @@ case OP_String: { /* out2 */
break;
}
+/* Opcode: BeginSubrtn * P2 * * *
+** Synopsis: r[P2]=NULL
+**
+** Mark the beginning of a subroutine that can be entered in-line
+** or that can be called using OP_Gosub. The subroutine should
+** be terminated by an OP_Return instruction that has a P1 operand that
+** is the same as the P2 operand to this opcode and that has P3 set to 1.
+** If the subroutine is entered in-line, then the OP_Return will simply
+** fall through. But if the subroutine is entered using OP_Gosub, then
+** the OP_Return will jump back to the first instruction after the OP_Gosub.
+**
+** This routine works by loading a NULL into the P2 register. When the
+** return address register contains a NULL, the OP_Return instruction is
+** a no-op that simply falls through to the next instruction (assuming that
+** the OP_Return opcode has a P3 value of 1). Thus if the subroutine is
+** entered in-line, then the OP_Return will cause in-line execution to
+** continue. But if the subroutine is entered via OP_Gosub, then the
+** OP_Return will cause a return to the address following the OP_Gosub.
+**
+** This opcode is identical to OP_Null. It has a different name
+** only to make the byte code easier to read and verify.
+*/
/* Opcode: Null P1 P2 P3 * *
** Synopsis: r[P2..P3]=NULL
**
@@ -1331,6 +1346,7 @@ case OP_String: { /* out2 */
** NULL values will not compare equal even if SQLITE_NULLEQ is set on
** OP_Ne or OP_Eq.
*/
+case OP_BeginSubrtn:
case OP_Null: { /* out2 */
int cnt;
u16 nullFlag;
diff --git a/src/where.c b/src/where.c
index 7b37db215..8755ccd2c 100644
--- a/src/where.c
+++ b/src/where.c
@@ -5883,7 +5883,7 @@ WhereInfo *sqlite3WhereBegin(
pRJ->regBloom = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
pRJ->regReturn = ++pParse->nMem;
- pRJ->addrInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, pRJ->regReturn);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
assert( pTab==pTabItem->pTab );
if( HasRowid(pTab) ){
KeyInfo *pInfo;
@@ -6022,12 +6022,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Terminate the subroutine that forms the interior of the loop of
** the RIGHT JOIN table */
WhereRightJoin *pRJ = pLevel->pRJ;
- int addrHere = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeChangeP1(v, pRJ->addrSubrtn-1, addrHere);
- sqlite3VdbeChangeP1(v, pRJ->addrInit, addrHere);
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
pLevel->addrCont = 0;
- sqlite3VdbeAddOp2(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn);
+ sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
+ VdbeCoverage(v);
assert( pParse->withinRJSubrtn>0 );
pParse->withinRJSubrtn--;
}
diff --git a/src/whereInt.h b/src/whereInt.h
index c8a188f80..acc9ec3dd 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -52,7 +52,6 @@ struct WhereRightJoin {
int regBloom; /* Bloom filter for iRJMatch */
int regReturn; /* Return register for the interior subroutine */
int addrSubrtn; /* Starting address for the interior subroutine */
- int addrInit; /* OP_Integer used for early init of regReturn */
};
/*