aboutsummaryrefslogtreecommitdiff
path: root/src/backend/jit/llvm/llvmjit_expr.c
diff options
context:
space:
mode:
authorDaniel Gustafsson <dgustafsson@postgresql.org>2023-09-27 13:02:21 +0200
committerDaniel Gustafsson <dgustafsson@postgresql.org>2023-09-27 13:02:21 +0200
commit9dce22033d5d2813e9f8e7d595f57ee5a38b3f8e (patch)
tree3027d39cfe18ebf288837ea30600dee90fb36eb2 /src/backend/jit/llvm/llvmjit_expr.c
parentef668d8bf56e8c164ed62acdb269aa2f7e7ad5a1 (diff)
downloadpostgresql-9dce22033d5d2813e9f8e7d595f57ee5a38b3f8e.tar.gz
postgresql-9dce22033d5d2813e9f8e7d595f57ee5a38b3f8e.zip
llvmjit: Use explicit LLVMContextRef for inlining
When performing inlining LLVM unfortunately "leaks" types (the types survive and are usable, but a new round of inlining will recreate new structurally equivalent types). This accumulation will over time amount to a memory leak which for some queries can be large enough to trigger the OOM process killer. To avoid accumulation of types, all IR related data is stored in an LLVMContextRef which is dropped and recreated in order to release all types. Dropping and recreating incurs overhead, so it will be done only after 100 queries. This is a heuristic which might be revisited, but until we can get the size of the context from LLVM we are flying a bit blind. This issue has been reported several times, there may be more references to it in the archives on top of the threads linked below. Backpatching of this fix will be handled once it has matured in master for a bit. Reported-By: Justin Pryzby <pryzby@telsasoft.com> Reported-By: Kurt Roeckx <kurt@roeckx.be> Reported-By: Jaime Casanova <jcasanov@systemguards.com.ec> Reported-By: Lauri Laanmets <pcspets@gmail.com> Author: Andres Freund and Daniel Gustafsson Discussion: https://postgr.es/m/7acc8678-df5f-4923-9cf6-e843131ae89d@www.fastmail.com Discussion: https://postgr.es/m/20201218235607.GC30237@telsasoft.com Discussion: https://postgr.es/m/CAPH-tTxLf44s3CvUUtQpkDr1D8Hxqc2NGDzGXS1ODsfiJ6WSqA@mail.gmail.com
Diffstat (limited to 'src/backend/jit/llvm/llvmjit_expr.c')
-rw-r--r--src/backend/jit/llvm/llvmjit_expr.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 2ac335e2389..4b51aa1ce07 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -84,6 +84,7 @@ llvm_compile_expr(ExprState *state)
LLVMBuilderRef b;
LLVMModuleRef mod;
+ LLVMContextRef lc;
LLVMValueRef eval_fn;
LLVMBasicBlockRef entry;
LLVMBasicBlockRef *opblocks;
@@ -145,8 +146,9 @@ llvm_compile_expr(ExprState *state)
INSTR_TIME_SET_CURRENT(starttime);
mod = llvm_mutable_module(context);
+ lc = LLVMGetModuleContext(mod);
- b = LLVMCreateBuilder();
+ b = LLVMCreateBuilderInContext(lc);
funcname = llvm_expand_funcname(context, "evalexpr");
@@ -157,7 +159,7 @@ llvm_compile_expr(ExprState *state)
LLVMSetVisibility(eval_fn, LLVMDefaultVisibility);
llvm_copy_attributes(AttributeTemplate, eval_fn);
- entry = LLVMAppendBasicBlock(eval_fn, "entry");
+ entry = LLVMAppendBasicBlockInContext(lc, eval_fn, "entry");
/* build state */
v_state = LLVMGetParam(eval_fn, 0);
@@ -303,7 +305,7 @@ llvm_compile_expr(ExprState *state)
"");
LLVMBuildCondBr(b,
LLVMBuildICmp(b, LLVMIntUGE, v_nvalid,
- l_int16_const(op->d.fetch.last_var),
+ l_int16_const(lc, op->d.fetch.last_var),
""),
opblocks[opno + 1], b_fetch);
@@ -341,7 +343,7 @@ llvm_compile_expr(ExprState *state)
LLVMValueRef params[2];
params[0] = v_slot;
- params[1] = l_int32_const(op->d.fetch.last_var);
+ params[1] = l_int32_const(lc, op->d.fetch.last_var);
LLVMBuildCall(b,
llvm_pg_func(mod, "slot_getsomeattrs_int"),
@@ -378,7 +380,7 @@ llvm_compile_expr(ExprState *state)
v_nulls = v_scannulls;
}
- v_attnum = l_int32_const(op->d.var.attnum);
+ v_attnum = l_int32_const(lc, op->d.var.attnum);
value = l_load_gep1(b, v_values, v_attnum, "");
isnull = l_load_gep1(b, v_nulls, v_attnum, "");
LLVMBuildStore(b, value, v_resvaluep);
@@ -444,12 +446,12 @@ llvm_compile_expr(ExprState *state)
}
/* load data */
- v_attnum = l_int32_const(op->d.assign_var.attnum);
+ v_attnum = l_int32_const(lc, op->d.assign_var.attnum);
v_value = l_load_gep1(b, v_values, v_attnum, "");
v_isnull = l_load_gep1(b, v_nulls, v_attnum, "");
/* compute addresses of targets */
- v_resultnum = l_int32_const(op->d.assign_var.resultnum);
+ v_resultnum = l_int32_const(lc, op->d.assign_var.resultnum);
v_rvaluep = LLVMBuildGEP(b, v_resultvalues,
&v_resultnum, 1, "");
v_risnullp = LLVMBuildGEP(b, v_resultnulls,
@@ -478,7 +480,7 @@ llvm_compile_expr(ExprState *state)
v_isnull = LLVMBuildLoad(b, v_tmpisnullp, "");
/* compute addresses of targets */
- v_resultnum = l_int32_const(resultnum);
+ v_resultnum = l_int32_const(lc, resultnum);
v_rvaluep =
LLVMBuildGEP(b, v_resultvalues, &v_resultnum, 1, "");
v_risnullp =
@@ -1703,7 +1705,7 @@ llvm_compile_expr(ExprState *state)
v_cmpresult =
LLVMBuildTrunc(b,
LLVMBuildLoad(b, v_resvaluep, ""),
- LLVMInt32Type(), "");
+ LLVMInt32TypeInContext(lc), "");
switch (rctype)
{
@@ -1729,7 +1731,7 @@ llvm_compile_expr(ExprState *state)
v_result = LLVMBuildICmp(b,
predicate,
v_cmpresult,
- l_int32_const(0),
+ l_int32_const(lc, 0),
"");
v_result = LLVMBuildZExt(b, v_result, TypeSizeT, "");
@@ -1872,7 +1874,7 @@ llvm_compile_expr(ExprState *state)
LLVMValueRef value,
isnull;
- v_aggno = l_int32_const(op->d.aggref.aggno);
+ v_aggno = l_int32_const(lc, op->d.aggref.aggno);
/* load agg value / null */
value = l_load_gep1(b, v_aggvalues, v_aggno, "aggvalue");
@@ -1906,7 +1908,7 @@ llvm_compile_expr(ExprState *state)
* expression). So load it from memory each time round.
*/
v_wfuncnop = l_ptr_const(&wfunc->wfuncno,
- l_ptr(LLVMInt32Type()));
+ l_ptr(LLVMInt32TypeInContext(lc)));
v_wfuncno = LLVMBuildLoad(b, v_wfuncnop, "v_wfuncno");
/* load window func value / null */
@@ -2014,7 +2016,7 @@ llvm_compile_expr(ExprState *state)
/* strict function, check for NULL args */
for (int argno = 0; argno < nargs; argno++)
{
- LLVMValueRef v_argno = l_int32_const(argno);
+ LLVMValueRef v_argno = l_int32_const(lc, argno);
LLVMValueRef v_argisnull;
LLVMBasicBlockRef b_argnotnull;
@@ -2071,7 +2073,7 @@ llvm_compile_expr(ExprState *state)
FIELDNO_AGGSTATE_ALL_PERGROUPS,
"aggstate.all_pergroups");
- v_setoff = l_int32_const(op->d.agg_plain_pergroup_nullcheck.setoff);
+ v_setoff = l_int32_const(lc, op->d.agg_plain_pergroup_nullcheck.setoff);
v_pergroup_allaggs = l_load_gep1(b, v_allpergroupsp, v_setoff, "");
@@ -2139,8 +2141,8 @@ llvm_compile_expr(ExprState *state)
l_load_struct_gep(b, v_aggstatep,
FIELDNO_AGGSTATE_ALL_PERGROUPS,
"aggstate.all_pergroups");
- v_setoff = l_int32_const(op->d.agg_trans.setoff);
- v_transno = l_int32_const(op->d.agg_trans.transno);
+ v_setoff = l_int32_const(lc, op->d.agg_trans.setoff);
+ v_transno = l_int32_const(lc, op->d.agg_trans.transno);
v_pergroupp =
LLVMBuildGEP(b,
l_load_gep1(b, v_allpergroupsp, v_setoff, ""),
@@ -2243,7 +2245,7 @@ llvm_compile_expr(ExprState *state)
/* set aggstate globals */
LLVMBuildStore(b, v_aggcontext, v_curaggcontext);
- LLVMBuildStore(b, l_int32_const(op->d.agg_trans.setno),
+ LLVMBuildStore(b, l_int32_const(lc, op->d.agg_trans.setno),
v_current_setp);
LLVMBuildStore(b, v_pertransp, v_current_pertransp);
@@ -2479,11 +2481,14 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
LLVMModuleRef mod, FunctionCallInfo fcinfo,
LLVMValueRef *v_fcinfo_isnull)
{
+ LLVMContextRef lc;
LLVMValueRef v_fn;
LLVMValueRef v_fcinfo_isnullp;
LLVMValueRef v_retval;
LLVMValueRef v_fcinfo;
+ lc = LLVMGetModuleContext(mod);
+
v_fn = llvm_function_reference(context, b, mod, fcinfo);
v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
@@ -2505,12 +2510,12 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
LLVMValueRef v_lifetime = create_LifetimeEnd(mod);
LLVMValueRef params[2];
- params[0] = l_int64_const(sizeof(NullableDatum) * fcinfo->nargs);
- params[1] = l_ptr_const(fcinfo->args, l_ptr(LLVMInt8Type()));
+ params[0] = l_int64_const(lc, sizeof(NullableDatum) * fcinfo->nargs);
+ params[1] = l_ptr_const(fcinfo->args, l_ptr(LLVMInt8TypeInContext(lc)));
LLVMBuildCall(b, v_lifetime, params, lengthof(params), "");
- params[0] = l_int64_const(sizeof(fcinfo->isnull));
- params[1] = l_ptr_const(&fcinfo->isnull, l_ptr(LLVMInt8Type()));
+ params[0] = l_int64_const(lc, sizeof(fcinfo->isnull));
+ params[1] = l_ptr_const(&fcinfo->isnull, l_ptr(LLVMInt8TypeInContext(lc)));
LLVMBuildCall(b, v_lifetime, params, lengthof(params), "");
}
@@ -2556,6 +2561,7 @@ create_LifetimeEnd(LLVMModuleRef mod)
LLVMTypeRef sig;
LLVMValueRef fn;
LLVMTypeRef param_types[2];
+ LLVMContextRef lc;
/* LLVM 5+ has a variadic pointer argument */
#if LLVM_VERSION_MAJOR < 5
@@ -2568,12 +2574,12 @@ create_LifetimeEnd(LLVMModuleRef mod)
if (fn)
return fn;
- param_types[0] = LLVMInt64Type();
- param_types[1] = l_ptr(LLVMInt8Type());
+ lc = LLVMGetModuleContext(mod);
+ param_types[0] = LLVMInt64TypeInContext(lc);
+ param_types[1] = l_ptr(LLVMInt8TypeInContext(lc));
- sig = LLVMFunctionType(LLVMVoidType(),
- param_types, lengthof(param_types),
- false);
+ sig = LLVMFunctionType(LLVMVoidTypeInContext(lc), param_types,
+ lengthof(param_types), false);
fn = LLVMAddFunction(mod, nm, sig);
LLVMSetFunctionCallConv(fn, LLVMCCallConv);