diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 4cf0883435..ba129948ef 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -3,26 +3,26 @@ * execExpr.c * Expression evaluation infrastructure. * - * Expression evaluation now works by first converting expression trees + * Expression evaluation works by first converting the expression tree * (which went through planning first) into an ExprState using ExecInitExpr() * et al. This converts the tree into a opcode based program (ExprEvalStep - * representing individual instructions); allocated as a flat array of + * representing individual instructions), allocated as a flat array of * steps. * * This flat representation has the big advantage that it can be implemented * non-recursively, within a single function. This allows to interpret * larger expressions from largely within a single function, keeping state - * between them. In contrast to that, tree-walk based approaches in contrast + * between them. In contrast to that, tree-walk based approaches * often run into performance issues due to function call / stack * manipulation overhead. * * The ExprEvalStep representation is designed to be usable for interpreting - * the expression, as well as compiling into native code. Thus, if possible, - * as much complexity as possible should be handed by ExecInitExpr() (and - * helpers), instead of handled at execution time where both interpreted and + * the expression, as well as compiling into native code. As much complexity + * as possible should be handled by ExecInitExpr() (and + * helpers), instead of execution time where both interpreted and * compiled versions would need to deal with the complexity. Additionally * checks for initialization at run time have a small but noticeable cost at - * every execution. + * every execution. (HEIKKI: What does this last sentence refer to?) * * The next step is preparing the ExprState for execution, using * ExecInstantiateExpr(). This is internally done by ExecInitExpr() and other diff --git a/src/backend/executor/execInterpExpr.c b/src/backend/executor/execInterpExpr.c index 21388f4086..2386fc898f 100644 --- a/src/backend/executor/execInterpExpr.c +++ b/src/backend/executor/execInterpExpr.c @@ -1,3 +1,7 @@ +/* + * HEIKKI: "Interp" is quite a mouthful. How about execExprInterpreter.c or + * just exprInterpreter.c? + */ /*------------------------------------------------------------------------- * * execInterpExpr.c @@ -5,19 +9,19 @@ * * This file provides a "switch threaded" (all compilers) and "direct * threaded" (gcc, clang and compatible) implementation of expression - * evaluation. The former is among st the fastest known methods of + * evaluation. The former is amongst the fastest known methods of * interpreting programs without resorting to assembly level work, or * just-in-time compilation, but requires support for computed gotos. The * latter is amongst the fastest approaches doable in standard C. * * Both work by using ExprEvalStep->opcode to dispatch into code blocks - * implementing the specific method. Switch based uses a plain switch() + * implementing the specific method. Switch-based uses a plain switch() * statement to perform the dispatch. This has the advantages of being plain C * and allowing to warn if implementation of a specific opcode has been * forgotten. The disadvantage is that dispatches will, as commonly * implemented by compilers, happen from a single location, causing bad branch * prediction. Direct dispatch uses the label-as-values gcc extension - also - * adopted by some other compilers - to replace ExprEvalStep-> opcode with the + * adopted by some other compilers - to replace ExprEvalStep->opcode with the * address of the block implementing the instruction. This allows for better * branch prediction (the jumps are happening from different locations) and * fewer jumps (no jumps to common dispatch location needed). @@ -84,26 +88,31 @@ */ #if defined(EEO_USE_COMPUTED_GOTO) static void **dispatch_table = NULL; -#define EEO_SWITCH(d) -#define EEO_DISPATCH_DIRECT(op) goto *((void *) op->opcode) +#define EEO_DISPATCH() goto *((void *) op->opcode) #define EEO_CASE(name) CASE_##name: #else -#define EEO_SWITCH(d) switch ((ExprEvalOp) d) -#define EEO_DISPATCH_DIRECT(op) goto starteval +#define EEO_DISPATCH() goto starteval #define EEO_CASE(name) case name: #endif /* EEO_USE_COMPUTED_GOTO */ -#define EEO_DISPATCH(op) \ +#define EEO_JUMP(stepno) \ + do \ + { \ + op = &state->steps[stepno]; \ + EEO_DISPATCH(); \ + } while (0) + +#define EEO_NEXT() \ do \ { \ op++; \ - EEO_DISPATCH_DIRECT(op); \ + EEO_DISPATCH(); \ } \ while (0) static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull); -static void ExecPrepareInterp(void); +static void ExecInitInterpreter(void); /* support functions */ static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, bool checkisnull); @@ -127,10 +136,11 @@ static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool void ExecInstantiateInterpretedExpr(ExprState *state) { - ExecPrepareInterp(); + ExecInitInterpreter(); Assert(state->steps_len >= 1); - Assert(ExecEvalStepOp(state, &state->steps[state->steps_len - 1]) == EEO_DONE); + Assert(state->steps[state->steps_len - 1].opcode == EEO_DONE); + Assert(state->flags & EEO_FLAG_JUMP_THREADED == 0); /* * Fast-path for very simple expressions. "starting up" the full @@ -141,8 +151,8 @@ ExecInstantiateInterpretedExpr(ExprState *state) */ if (state->steps_len == 3) { - ExprEvalOp step0 = ExecEvalStepOp(state, &state->steps[0]); - ExprEvalOp step1 = ExecEvalStepOp(state, &state->steps[1]); + ExprEvalOp step0 = state->steps[0].opcode; + ExprEvalOp step1 = state->steps[1].opcode; if (step0 == EEO_INNER_FETCHSOME && step1 == EEO_INNER_VAR) { @@ -176,7 +186,7 @@ ExecInstantiateInterpretedExpr(ExprState *state) } } else if (state->steps_len == 2 && - ExecEvalStepOp(state, &state->steps[0]) == EEO_CONST) + state->steps[0].opcode == EEO_CONST) { state->evalfunc = ExecJustConst; return; @@ -319,11 +329,11 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) scanslot = econtext->ecxt_scantuple; #if defined(EEO_USE_COMPUTED_GOTO) - EEO_DISPATCH_DIRECT(op); + EEO_DISPATCH(); #else starteval: + switch ((ExprEvalOp) op->opcode) #endif - EEO_SWITCH(op->opcode) { EEO_CASE(EEO_DONE) { @@ -335,21 +345,21 @@ starteval: /* XXX: worthwhile to check tts_nvalid inline first? */ slot_getsomeattrs(innerslot, op->d.fetch.last_var); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_OUTER_FETCHSOME) { slot_getsomeattrs(outerslot, op->d.fetch.last_var); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_SCAN_FETCHSOME) { slot_getsomeattrs(scanslot, op->d.fetch.last_var); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_INNER_VAR) @@ -365,7 +375,7 @@ starteval: *op->resnull = innerslot->tts_isnull[attnum]; *op->resvalue = innerslot->tts_values[attnum]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_OUTER_VAR) @@ -377,7 +387,7 @@ starteval: *op->resnull = outerslot->tts_isnull[attnum]; *op->resvalue = outerslot->tts_values[attnum]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_SCAN_VAR) @@ -389,7 +399,7 @@ starteval: *op->resnull = scanslot->tts_isnull[attnum]; *op->resvalue = scanslot->tts_values[attnum]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ASSIGN_INNER_VAR) @@ -400,7 +410,7 @@ starteval: resultslot->tts_values[resultnum] = innerslot->tts_values[attnum]; resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ASSIGN_OUTER_VAR) @@ -411,7 +421,7 @@ starteval: resultslot->tts_values[resultnum] = outerslot->tts_values[attnum]; resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ASSIGN_SCAN_VAR) @@ -422,7 +432,7 @@ starteval: resultslot->tts_values[resultnum] = scanslot->tts_values[attnum]; resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ASSIGN_TMP) @@ -432,7 +442,7 @@ starteval: resultslot->tts_values[resultnum] = state->resvalue; resultslot->tts_isnull[resultnum] = state->resnull; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ASSIGN_TMP_UNEXPAND) @@ -447,7 +457,7 @@ starteval: else resultslot->tts_values[resultnum] = state->resvalue; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_INNER_SYSVAR) @@ -459,7 +469,7 @@ starteval: innerslot->tts_tupleDescriptor, op->resnull); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_OUTER_SYSVAR) @@ -471,7 +481,7 @@ starteval: scanslot->tts_tupleDescriptor, op->resnull); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_SCAN_SYSVAR) @@ -483,7 +493,7 @@ starteval: scanslot->tts_tupleDescriptor, op->resnull); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_CONST) @@ -491,7 +501,7 @@ starteval: *op->resnull = op->d.constval.isnull; *op->resvalue = op->d.constval.value; - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -510,7 +520,7 @@ starteval: *op->resvalue = (op->d.func.fn_addr) (fcinfo); *op->resnull = fcinfo->isnull; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_FUNCEXPR_STRICT) @@ -533,7 +543,7 @@ starteval: *op->resnull = fcinfo->isnull; strictfail: - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_FUNCEXPR_FUSAGE) @@ -549,7 +559,7 @@ starteval: pgstat_end_function_usage(&fcusage, true); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_FUNCEXPR_STRICT_FUSAGE) @@ -577,7 +587,7 @@ starteval: strictfail_fusage: pgstat_end_function_usage(&fcusage, true); - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -608,12 +618,10 @@ starteval: *op->resnull = false; *op->resvalue = BoolGetDatum(false); /* bail out early */ - op = &state->steps[op->d.boolexpr.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.boolexpr.jumpdone); } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOL_AND_STEP_LAST) @@ -645,7 +653,7 @@ starteval: *op->resvalue = BoolGetDatum(true); } - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -683,12 +691,10 @@ starteval: *op->resvalue = BoolGetDatum(true); /* bail out early */ - op = &state->steps[op->d.boolexpr.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.boolexpr.jumpdone); } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOL_OR_STEP_LAST) @@ -720,7 +726,7 @@ starteval: *op->resvalue = BoolGetDatum(false); } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOL_NOT_STEP) @@ -737,7 +743,7 @@ starteval: */ *op->resvalue = BoolGetDatum(!DatumGetBool(*op->d.boolexpr.value)); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_QUAL) @@ -750,12 +756,10 @@ starteval: /* bail out early */ *op->resnull = false; *op->resvalue = BoolGetDatum(false); - op = &state->steps[op->d.qualexpr.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.qualexpr.jumpdone); } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_NULLTEST_ISNULL) @@ -763,7 +767,7 @@ starteval: *op->resvalue = BoolGetDatum(*op->resnull); *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_NULLTEST_ISNOTNULL) @@ -771,7 +775,7 @@ starteval: *op->resvalue = BoolGetDatum(!*op->resnull); *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_NULLTEST_ROWISNULL) @@ -779,7 +783,7 @@ starteval: /* out of line implementation: too large */ ExecEvalRowNull(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_NULLTEST_ROWISNOTNULL) @@ -787,7 +791,7 @@ starteval: /* out of line implementation: too large */ ExecEvalRowNotNull(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_PARAM_EXEC) @@ -795,14 +799,14 @@ starteval: /* out of line implementation: too large */ ExecEvalParamExec(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_PARAM_EXTERN) { /* out of line implementation: too large */ ExecEvalParamExtern(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_CASE_WHEN_STEP) @@ -810,22 +814,18 @@ starteval: if (!*op->d.casewhen.isnull && DatumGetBool(*op->d.casewhen.value)) { - EEO_DISPATCH(op); + EEO_NEXT(); } else { - op = &state->steps[op->d.casewhen.jumpfalse]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.casewhen.jumpfalse); } } EEO_CASE(EEO_CASE_THEN_STEP) { /* results already placed in correct place during preceding steps */ - op = &state->steps[op->d.casethen.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.casethen.jumpdone); } EEO_CASE(EEO_CASE_TESTVAL) @@ -850,7 +850,7 @@ starteval: *op->resnull = econtext->caseValue_isNull; } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_CASE_TESTVAL_UNEXPAND) @@ -876,7 +876,7 @@ starteval: MakeExpandedObjectReadOnlyInternal(*op->resvalue); } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_DOMAIN_TESTVAL) @@ -895,7 +895,7 @@ starteval: *op->resnull = econtext->domainValue_isNull; } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_DOMAIN_TESTVAL_UNEXPAND) @@ -924,7 +924,7 @@ starteval: MakeExpandedObjectReadOnlyInternal(*op->resvalue); } - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -935,12 +935,10 @@ starteval: { if (!*op->resnull) { - op = &state->steps[op->d.coalesce.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.coalesce.jumpdone); } - EEO_DISPATCH(op); + EEO_NEXT(); } /* BooleanTest implementations for all booltesttypes */ @@ -952,7 +950,7 @@ starteval: *op->resvalue = *op->resvalue; *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOLTEST_IS_NOT_FALSE) @@ -963,7 +961,7 @@ starteval: *op->resvalue = *op->resvalue; *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOLTEST_IS_FALSE) @@ -974,7 +972,7 @@ starteval: *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOLTEST_IS_NOT_TRUE) @@ -985,7 +983,7 @@ starteval: *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOLTEST_IS_UNKNOWN) @@ -993,7 +991,7 @@ starteval: *op->resvalue = BoolGetDatum(*op->resnull); *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_BOOLTEST_IS_NOT_UNKNOWN) @@ -1001,7 +999,7 @@ starteval: *op->resvalue = BoolGetDatum(!*op->resnull); *op->resnull = false; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_WHOLEROW) @@ -1009,7 +1007,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalWholeRowVar(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1068,7 +1066,7 @@ starteval: } - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1106,7 +1104,7 @@ starteval: *op->resnull = fcinfo->isnull; } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_NULLIF) @@ -1127,13 +1125,13 @@ starteval: *op->resnull = true; *op->resvalue = true; - EEO_DISPATCH(op); + EEO_NEXT(); } } *op->resnull = fcinfo->argnull[0]; *op->resvalue = fcinfo->arg[0]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_SQLVALUEFUNCTION) @@ -1144,7 +1142,7 @@ starteval: */ ExecEvalSQLValueFunction(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_CURRENTOFEXPR) @@ -1152,7 +1150,7 @@ starteval: /* error invocation uses space, and shouldn't ever occur */ ExecEvalCurrentOfExpr(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ARRAYEXPR) @@ -1160,7 +1158,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalArrayExpr(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ARRAYCOERCE) @@ -1168,7 +1166,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalArrayCoerce(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ROW) @@ -1176,7 +1174,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalRow(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ROWCOMPARE_STEP) @@ -1188,9 +1186,7 @@ starteval: (fcinfo->argnull[0] || fcinfo->argnull[1])) { *op->resnull = true; - op = &state->steps[op->d.rowcompare_step.jumpnull]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.rowcompare_step.jumpnull); } fcinfo->isnull = false; @@ -1200,20 +1196,16 @@ starteval: if (fcinfo->isnull) { *op->resnull = true; - op = &state->steps[op->d.rowcompare_step.jumpnull]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.rowcompare_step.jumpnull); } /* no need to compare remaining columns */ if (DatumGetInt32(*op->resvalue) != 0) { - op = &state->steps[op->d.rowcompare_step.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.rowcompare_step.jumpdone); } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ROWCOMPARE_FINAL) @@ -1242,7 +1234,7 @@ starteval: break; } - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_MINMAX) @@ -1250,7 +1242,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalMinMax(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_FIELDSELECT) @@ -1258,7 +1250,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalFieldSelect(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_FIELDSTORE_DEFORM) @@ -1266,7 +1258,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalFieldStoreDeForm(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_FIELDSTORE_FORM) @@ -1274,7 +1266,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalFieldStoreForm(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1291,12 +1283,10 @@ starteval: if (*op->resnull && !op->d.arrayref.state->isassignment) { - op = &state->steps[op->d.arrayref.jumpdone]; - - EEO_DISPATCH_DIRECT(op); + EEO_JUMP(op->d.arrayref.jumpdone); } - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1307,14 +1297,12 @@ starteval: /* too complex for an inline implementation */ if (ExecEvalArrayRefCheckSubscript(state, op)) { - op++; + EEO_NEXT(); } else { - op = &state->steps[op->d.arrayref_checksubscript.jumpdone]; + EEO_JUMP(op->d.arrayref_checksubscript.jumpdone); } - - EEO_DISPATCH_DIRECT(op); } /* @@ -1326,7 +1314,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalArrayRefOld(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1337,7 +1325,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalArrayRefAssign(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1348,7 +1336,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalArrayRefFetch(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_CONVERT_ROWTYPE) @@ -1356,7 +1344,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalConvertRowtype(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_SCALARARRAYOP) @@ -1364,14 +1352,14 @@ starteval: /* too complex for an inline implementation */ ExecEvalScalarArrayOp(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_DOMAIN_NOTNULL) { /* too complex for an inline implementation */ ExecEvalConstraintNotNull(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_DOMAIN_CHECK) @@ -1379,7 +1367,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalConstraintCheck(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_XMLEXPR) @@ -1387,7 +1375,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalXmlExpr(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } /* @@ -1403,7 +1391,7 @@ starteval: *op->resnull = econtext->ecxt_aggnulls[aggref->aggno]; *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_GROUPING_FUNC) @@ -1411,7 +1399,7 @@ starteval: /* too complex/uncommon for an inline implementation */ ExecEvalGroupingFunc(state, op); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_WINDOW_FUNC) @@ -1423,7 +1411,7 @@ starteval: *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno]; *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno]; - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_SUBPLAN) @@ -1431,7 +1419,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalSubPlan(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_ALTERNATIVE_SUBPLAN) @@ -1439,7 +1427,7 @@ starteval: /* too complex for an inline implementation */ ExecEvalAlternativeSubPlan(state, op, econtext); - EEO_DISPATCH(op); + EEO_NEXT(); } EEO_CASE(EEO_LAST) @@ -1454,6 +1442,8 @@ out: return state->resvalue; } +/* Fast-path functions, for very simple expressions */ + static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) { @@ -1536,7 +1526,7 @@ ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull) } static void -ExecPrepareInterp(void) +ExecInitInterpreter(void) { static bool prepared = false; @@ -1551,27 +1541,6 @@ ExecPrepareInterp(void) prepared = true; } -ExprEvalOp -ExecEvalStepOp(ExprState *state, ExprEvalStep *op) -{ -#if defined(EEO_USE_COMPUTED_GOTO) - if (state->flags & EEO_FLAG_JUMP_THREADED) - { - int i; - - for (i = 0; i < EEO_LAST; i++) - { - if ((void *) op->opcode == dispatch_table[i]) - { - return (ExprEvalOp) i; - } - } - elog(ERROR, "unknown opcode"); - } -#endif - return (ExprEvalOp) op->opcode; -} - /* * Computes the value for a PARAM_EXEC parameter. */ diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 003f4faede..e28bb2a85e 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -22,6 +22,11 @@ struct ArrayRefState; typedef enum ExprEvalOp { + /* + * HEIKKI: How about renaming these to EEOP_* ? I think it'd be a + * good mnemonic to remember that these are opcodes, and just one + * extra letter. + */ EEO_DONE, EEO_INNER_FETCHSOME, EEO_OUTER_FETCHSOME, @@ -110,6 +115,11 @@ typedef struct ExprEvalStep * ExprEvalOp, but during execution it can be swapped out to some other * type, e.g. a pointer for computed goto (that's why it's a size_t). */ + /* HEIKKI: Is it safe to assume that sizeof(size_t) >= sizeof(void *) ? */ + /* HEIKKI: How tight are we with space in this union? It'd be nice to keep + * the original opcode, and have a separate field for the computed goto ptr. + * For debugging purposes if nothing else. + */ size_t opcode; /* target for the result of the current instruction */ @@ -419,8 +429,6 @@ typedef struct ArrayRefState extern void ExecInstantiateInterpretedExpr(ExprState *state); -extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op); - /* * Non fast-path execution functions. These are externs instead of static in * execInterpExpr.c, because that allows them to be used by other methods of