Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8dd7c7c

Browse files
Replace EEOP_DONE with special steps for return/no return
Knowing when the side-effects of an expression is the intended result of the execution, rather than the returnvalue, is important for being able generate more efficient JITed code. This replaces EEOP_DONE with two new steps: EEOP_DONE_RETURN and EEOP_DONE_NO_RETURN. Expressions which return a value should use the former step; expressions used for their side-effects which don't return value should use the latter. Author: Andres Freund <andres@anarazel.de> Co-authored-by: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Andreas Karlsson <andreas@proxel.se> Discussion: https://postgr.es/m/415721CE-7D2E-4B74-B5D9-1950083BA03E@yesql.se Discussion: https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de
1 parent dabccf4 commit 8dd7c7c

File tree

7 files changed

+98
-34
lines changed

7 files changed

+98
-34
lines changed

src/backend/executor/README

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,14 @@ is used by the function evaluation step, thus avoiding extra work to copy
133133
the result values around.
134134

135135
The last entry in a completed ExprState->steps array is always an
136-
EEOP_DONE step; this removes the need to test for end-of-array while
137-
iterating. Also, if the expression contains any variable references (to
138-
user columns of the ExprContext's INNER, OUTER, or SCAN tuples), the steps
136+
EEOP_DONE_RETURN or EEOP_DONE_NO_RETURN step; this removes the need to
137+
test for end-of-array while iterating. The former is used when the
138+
expression returns a value directly, the latter when side-effects of
139+
expression initialization are the goal (e.g. for projection or
140+
aggregate transition value computation).
141+
142+
Also, if the expression contains any variable references (to user
143+
columns of the ExprContext's INNER, OUTER, or SCAN tuples), the steps
139144
array begins with EEOP_*_FETCHSOME steps that ensure that the relevant
140145
tuples have been deconstructed to make the required columns directly
141146
available (cf. slot_getsomeattrs()). This allows individual Var-fetching

src/backend/executor/execExpr.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* using ExecInitExpr() et al. This converts the tree into a flat array
99
* of ExprEvalSteps, which may be thought of as instructions in a program.
1010
* At runtime, we'll execute steps, starting with the first, until we reach
11-
* an EEOP_DONE opcode.
11+
* an EEOP_DONE_{RETURN|NO_RETURN} opcode.
1212
*
1313
* This file contains the "compilation" logic. It is independent of the
1414
* specific execution technology we use (switch statement, computed goto,
@@ -162,7 +162,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
162162
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
163163

164164
/* Finally, append a DONE step */
165-
scratch.opcode = EEOP_DONE;
165+
scratch.opcode = EEOP_DONE_RETURN;
166166
ExprEvalPushStep(state, &scratch);
167167

168168
ExecReadyExpr(state);
@@ -199,7 +199,7 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
199199
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
200200

201201
/* Finally, append a DONE step */
202-
scratch.opcode = EEOP_DONE;
202+
scratch.opcode = EEOP_DONE_RETURN;
203203
ExprEvalPushStep(state, &scratch);
204204

205205
ExecReadyExpr(state);
@@ -291,7 +291,7 @@ ExecInitQual(List *qual, PlanState *parent)
291291
* have yielded TRUE, and since its result is stored in the desired output
292292
* location, we're done.
293293
*/
294-
scratch.opcode = EEOP_DONE;
294+
scratch.opcode = EEOP_DONE_RETURN;
295295
ExprEvalPushStep(state, &scratch);
296296

297297
ExecReadyExpr(state);
@@ -503,7 +503,7 @@ ExecBuildProjectionInfo(List *targetList,
503503
}
504504
}
505505

506-
scratch.opcode = EEOP_DONE;
506+
scratch.opcode = EEOP_DONE_NO_RETURN;
507507
ExprEvalPushStep(state, &scratch);
508508

509509
ExecReadyExpr(state);
@@ -742,7 +742,7 @@ ExecBuildUpdateProjection(List *targetList,
742742
}
743743
}
744744

745-
scratch.opcode = EEOP_DONE;
745+
scratch.opcode = EEOP_DONE_NO_RETURN;
746746
ExprEvalPushStep(state, &scratch);
747747

748748
ExecReadyExpr(state);
@@ -1714,7 +1714,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
17141714
else
17151715
{
17161716
/* Not trivial, so append a DONE step */
1717-
scratch.opcode = EEOP_DONE;
1717+
scratch.opcode = EEOP_DONE_RETURN;
17181718
ExprEvalPushStep(elemstate, &scratch);
17191719
/* and ready the subexpression */
17201720
ExecReadyExpr(elemstate);
@@ -3991,7 +3991,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
39913991

39923992
scratch.resvalue = NULL;
39933993
scratch.resnull = NULL;
3994-
scratch.opcode = EEOP_DONE;
3994+
scratch.opcode = EEOP_DONE_NO_RETURN;
39953995
ExprEvalPushStep(state, &scratch);
39963996

39973997
ExecReadyExpr(state);
@@ -4258,7 +4258,7 @@ ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops,
42584258

42594259
scratch.resvalue = NULL;
42604260
scratch.resnull = NULL;
4261-
scratch.opcode = EEOP_DONE;
4261+
scratch.opcode = EEOP_DONE_RETURN;
42624262
ExprEvalPushStep(state, &scratch);
42634263

42644264
ExecReadyExpr(state);
@@ -4431,7 +4431,7 @@ ExecBuildHash32Expr(TupleDesc desc, const TupleTableSlotOps *ops,
44314431

44324432
scratch.resvalue = NULL;
44334433
scratch.resnull = NULL;
4434-
scratch.opcode = EEOP_DONE;
4434+
scratch.opcode = EEOP_DONE_RETURN;
44354435
ExprEvalPushStep(state, &scratch);
44364436

44374437
ExecReadyExpr(state);
@@ -4586,7 +4586,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
45864586

45874587
scratch.resvalue = NULL;
45884588
scratch.resnull = NULL;
4589-
scratch.opcode = EEOP_DONE;
4589+
scratch.opcode = EEOP_DONE_RETURN;
45904590
ExprEvalPushStep(state, &scratch);
45914591

45924592
ExecReadyExpr(state);
@@ -4722,7 +4722,7 @@ ExecBuildParamSetEqual(TupleDesc desc,
47224722

47234723
scratch.resvalue = NULL;
47244724
scratch.resnull = NULL;
4725-
scratch.opcode = EEOP_DONE;
4725+
scratch.opcode = EEOP_DONE_RETURN;
47264726
ExprEvalPushStep(state, &scratch);
47274727

47284728
ExecReadyExpr(state);

src/backend/executor/execExprInterp.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ ExecReadyInterpretedExpr(ExprState *state)
246246

247247
/* Simple validity checks on expression */
248248
Assert(state->steps_len >= 1);
249-
Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
249+
Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE_RETURN ||
250+
state->steps[state->steps_len - 1].opcode == EEOP_DONE_NO_RETURN);
250251

251252
/*
252253
* Don't perform redundant initialization. This is unreachable in current
@@ -469,7 +470,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
469470
*/
470471
#if defined(EEO_USE_COMPUTED_GOTO)
471472
static const void *const dispatch_table[] = {
472-
&&CASE_EEOP_DONE,
473+
&&CASE_EEOP_DONE_RETURN,
474+
&&CASE_EEOP_DONE_NO_RETURN,
473475
&&CASE_EEOP_INNER_FETCHSOME,
474476
&&CASE_EEOP_OUTER_FETCHSOME,
475477
&&CASE_EEOP_SCAN_FETCHSOME,
@@ -612,9 +614,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
612614

613615
EEO_SWITCH()
614616
{
615-
EEO_CASE(EEOP_DONE)
617+
EEO_CASE(EEOP_DONE_RETURN)
616618
{
617-
goto out;
619+
*isnull = state->resnull;
620+
return state->resvalue;
621+
}
622+
623+
EEO_CASE(EEOP_DONE_NO_RETURN)
624+
{
625+
Assert(isnull == NULL);
626+
return (Datum) 0;
618627
}
619628

620629
EEO_CASE(EEOP_INNER_FETCHSOME)
@@ -2188,13 +2197,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
21882197
{
21892198
/* unreachable */
21902199
Assert(false);
2191-
goto out;
2200+
goto out_error;
21922201
}
21932202
}
21942203

2195-
out:
2196-
*isnull = state->resnull;
2197-
return state->resvalue;
2204+
out_error:
2205+
pg_unreachable();
2206+
return (Datum) 0;
21982207
}
21992208

22002209
/*

src/backend/executor/nodeAgg.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -816,11 +816,8 @@ advance_transition_function(AggState *aggstate,
816816
static void
817817
advance_aggregates(AggState *aggstate)
818818
{
819-
bool dummynull;
820-
821-
ExecEvalExprSwitchContext(aggstate->phase->evaltrans,
822-
aggstate->tmpcontext,
823-
&dummynull);
819+
ExecEvalExprNoReturnSwitchContext(aggstate->phase->evaltrans,
820+
aggstate->tmpcontext);
824821
}
825822

826823
/*

src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ llvm_compile_expr(ExprState *state)
321321

322322
switch (opcode)
323323
{
324-
case EEOP_DONE:
324+
case EEOP_DONE_RETURN:
325325
{
326326
LLVMValueRef v_tmpisnull;
327327
LLVMValueRef v_tmpvalue;
@@ -335,6 +335,10 @@ llvm_compile_expr(ExprState *state)
335335
break;
336336
}
337337

338+
case EEOP_DONE_NO_RETURN:
339+
LLVMBuildRet(b, l_sizet_const(0));
340+
break;
341+
338342
case EEOP_INNER_FETCHSOME:
339343
case EEOP_OUTER_FETCHSOME:
340344
case EEOP_SCAN_FETCHSOME:

src/include/executor/execExpr.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ typedef struct ExprEvalRowtypeCache
6565
*/
6666
typedef enum ExprEvalOp
6767
{
68-
/* entire expression has been evaluated completely, return */
69-
EEOP_DONE,
68+
/* entire expression has been evaluated, return value */
69+
EEOP_DONE_RETURN,
70+
71+
/* entire expression has been evaluated, no return value */
72+
EEOP_DONE_NO_RETURN,
7073

7174
/* apply slot_getsomeattrs on corresponding tuple slot */
7275
EEOP_INNER_FETCHSOME,

src/include/executor/executor.h

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,34 @@ ExecEvalExpr(ExprState *state,
379379
}
380380
#endif
381381

382+
/*
383+
* ExecEvalExprNoReturn
384+
*
385+
* Like ExecEvalExpr(), but for cases where no return value is expected,
386+
* because the side-effects of expression evaluation are what's desired. This
387+
* is e.g. used for projection and aggregate transition computation.
388+
389+
* Evaluate expression identified by "state" in the execution context
390+
* given by "econtext".
391+
*
392+
* The caller should already have switched into the temporary memory context
393+
* econtext->ecxt_per_tuple_memory. The convenience entry point
394+
* ExecEvalExprNoReturnSwitchContext() is provided for callers who don't
395+
* prefer to do the switch in an outer loop.
396+
*/
397+
#ifndef FRONTEND
398+
static inline void
399+
ExecEvalExprNoReturn(ExprState *state,
400+
ExprContext *econtext)
401+
{
402+
PG_USED_FOR_ASSERTS_ONLY Datum retDatum;
403+
404+
retDatum = state->evalfunc(state, econtext, NULL);
405+
406+
Assert(retDatum == (Datum) 0);
407+
}
408+
#endif
409+
382410
/*
383411
* ExecEvalExprSwitchContext
384412
*
@@ -400,6 +428,25 @@ ExecEvalExprSwitchContext(ExprState *state,
400428
}
401429
#endif
402430

431+
/*
432+
* ExecEvalExprNoReturnSwitchContext
433+
*
434+
* Same as ExecEvalExprNoReturn, but get into the right allocation context
435+
* explicitly.
436+
*/
437+
#ifndef FRONTEND
438+
static inline void
439+
ExecEvalExprNoReturnSwitchContext(ExprState *state,
440+
ExprContext *econtext)
441+
{
442+
MemoryContext oldContext;
443+
444+
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
445+
ExecEvalExprNoReturn(state, econtext);
446+
MemoryContextSwitchTo(oldContext);
447+
}
448+
#endif
449+
403450
/*
404451
* ExecProject
405452
*
@@ -419,16 +466,15 @@ ExecProject(ProjectionInfo *projInfo)
419466
ExprContext *econtext = projInfo->pi_exprContext;
420467
ExprState *state = &projInfo->pi_state;
421468
TupleTableSlot *slot = state->resultslot;
422-
bool isnull;
423469

424470
/*
425471
* Clear any former contents of the result slot. This makes it safe for
426472
* us to use the slot's Datum/isnull arrays as workspace.
427473
*/
428474
ExecClearTuple(slot);
429475

430-
/* Run the expression, discarding scalar result from the last column. */
431-
(void) ExecEvalExprSwitchContext(state, econtext, &isnull);
476+
/* Run the expression */
477+
ExecEvalExprNoReturnSwitchContext(state, econtext);
432478

433479
/*
434480
* Successfully formed a result row. Mark the result slot as containing a

0 commit comments

Comments
 (0)