4242#include "utils/memutils.h"
4343#include "utils/resowner_private.h"
4444
45+ #define LLVMJIT_LLVM_CONTEXT_REUSE_MAX 100
46+
4547/* Handle of a module emitted via ORC JIT */
4648typedef struct LLVMJitHandle
4749{
@@ -81,8 +83,15 @@ static LLVMModuleRef llvm_types_module = NULL;
8183
8284static bool llvm_session_initialized = false;
8385static size_t llvm_generation = 0 ;
86+
87+ /* number of LLVMJitContexts that currently are in use */
88+ static size_t llvm_jit_context_in_use_count = 0 ;
89+
90+ /* how many times has the current LLVMContextRef been used */
91+ static size_t llvm_llvm_context_reuse_count = 0 ;
8492static const char * llvm_triple = NULL ;
8593static const char * llvm_layout = NULL ;
94+ static LLVMContextRef llvm_context ;
8695
8796
8897static LLVMTargetRef llvm_targetref ;
@@ -103,6 +112,8 @@ static void llvm_compile_module(LLVMJitContext *context);
103112static void llvm_optimize_module (LLVMJitContext * context , LLVMModuleRef module );
104113
105114static void llvm_create_types (void );
115+ static void llvm_set_target (void );
116+ static void llvm_recreate_llvm_context (void );
106117static uint64_t llvm_resolve_symbol (const char * name , void * ctx );
107118
108119#if LLVM_VERSION_MAJOR > 11
@@ -124,6 +135,63 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
124135 cb -> compile_expr = llvm_compile_expr ;
125136}
126137
138+
139+ /*
140+ * Every now and then create a new LLVMContextRef. Unfortunately, during every
141+ * round of inlining, types may "leak" (they can still be found/used via the
142+ * context, but new types will be created the next time in inlining is
143+ * performed). To prevent that from slowly accumulating problematic amounts of
144+ * memory, recreate the LLVMContextRef we use. We don't want to do so too
145+ * often, as that implies some overhead (particularly re-loading the module
146+ * summaries / modules is fairly expensive). A future TODO would be to make
147+ * this more finegrained and only drop/recreate the LLVMContextRef when we know
148+ * there has been inlining. If we can get the size of the context from LLVM
149+ * then that might be a better way to determine when to drop/recreate rather
150+ * then the usagecount heuristic currently employed.
151+ */
152+ static void
153+ llvm_recreate_llvm_context (void )
154+ {
155+ if (!llvm_context )
156+ elog (ERROR , "Trying to recreate a non-existing context" );
157+
158+ /*
159+ * We can only safely recreate the LLVM context if no other code is being
160+ * JITed, otherwise we'd release the types in use for that.
161+ */
162+ if (llvm_jit_context_in_use_count > 0 )
163+ {
164+ llvm_llvm_context_reuse_count ++ ;
165+ return ;
166+ }
167+
168+ if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX )
169+ {
170+ llvm_llvm_context_reuse_count ++ ;
171+ return ;
172+ }
173+
174+ /*
175+ * Need to reset the modules that the inlining code caches before
176+ * disposing of the context. LLVM modules exist within a specific LLVM
177+ * context, therefore disposing of the context before resetting the cache
178+ * would lead to dangling pointers to modules.
179+ */
180+ llvm_inline_reset_caches ();
181+
182+ LLVMContextDispose (llvm_context );
183+ llvm_context = LLVMContextCreate ();
184+ llvm_llvm_context_reuse_count = 0 ;
185+
186+ /*
187+ * Re-build cached type information, so code generation code can rely on
188+ * that information to be present (also prevents the variables to be
189+ * dangling references).
190+ */
191+ llvm_create_types ();
192+ }
193+
194+
127195/*
128196 * Create a context for JITing work.
129197 *
@@ -140,6 +208,8 @@ llvm_create_context(int jitFlags)
140208
141209 llvm_session_initialize ();
142210
211+ llvm_recreate_llvm_context ();
212+
143213 ResourceOwnerEnlargeJIT (CurrentResourceOwner );
144214
145215 context = MemoryContextAllocZero (TopMemoryContext ,
@@ -150,6 +220,8 @@ llvm_create_context(int jitFlags)
150220 context -> base .resowner = CurrentResourceOwner ;
151221 ResourceOwnerRememberJIT (CurrentResourceOwner , PointerGetDatum (context ));
152222
223+ llvm_jit_context_in_use_count ++ ;
224+
153225 return context ;
154226}
155227
@@ -159,9 +231,15 @@ llvm_create_context(int jitFlags)
159231static void
160232llvm_release_context (JitContext * context )
161233{
162- LLVMJitContext * llvm_context = (LLVMJitContext * ) context ;
234+ LLVMJitContext * llvm_jit_context = (LLVMJitContext * ) context ;
163235 ListCell * lc ;
164236
237+ /*
238+ * Consider as cleaned up even if we skip doing so below, that way we can
239+ * verify the tracking is correct (see llvm_shutdown()).
240+ */
241+ llvm_jit_context_in_use_count -- ;
242+
165243 /*
166244 * When this backend is exiting, don't clean up LLVM. As an error might
167245 * have occurred from within LLVM, we do not want to risk reentering. All
@@ -172,13 +250,13 @@ llvm_release_context(JitContext *context)
172250
173251 llvm_enter_fatal_on_oom ();
174252
175- if (llvm_context -> module )
253+ if (llvm_jit_context -> module )
176254 {
177- LLVMDisposeModule (llvm_context -> module );
178- llvm_context -> module = NULL ;
255+ LLVMDisposeModule (llvm_jit_context -> module );
256+ llvm_jit_context -> module = NULL ;
179257 }
180258
181- foreach (lc , llvm_context -> handles )
259+ foreach (lc , llvm_jit_context -> handles )
182260 {
183261 LLVMJitHandle * jit_handle = (LLVMJitHandle * ) lfirst (lc );
184262
@@ -208,8 +286,8 @@ llvm_release_context(JitContext *context)
208286
209287 pfree (jit_handle );
210288 }
211- list_free (llvm_context -> handles );
212- llvm_context -> handles = NIL ;
289+ list_free (llvm_jit_context -> handles );
290+ llvm_jit_context -> handles = NIL ;
213291
214292 llvm_leave_fatal_on_oom ();
215293}
@@ -229,7 +307,7 @@ llvm_mutable_module(LLVMJitContext *context)
229307 {
230308 context -> compiled = false;
231309 context -> module_generation = llvm_generation ++ ;
232- context -> module = LLVMModuleCreateWithName ("pg" );
310+ context -> module = LLVMModuleCreateWithNameInContext ("pg" , llvm_context );
233311 LLVMSetTarget (context -> module , llvm_triple );
234312 LLVMSetDataLayout (context -> module , llvm_layout );
235313 }
@@ -787,6 +865,14 @@ llvm_session_initialize(void)
787865 LLVMInitializeNativeAsmPrinter ();
788866 LLVMInitializeNativeAsmParser ();
789867
868+ if (llvm_context == NULL )
869+ {
870+ llvm_context = LLVMContextCreate ();
871+
872+ llvm_jit_context_in_use_count = 0 ;
873+ llvm_llvm_context_reuse_count = 0 ;
874+ }
875+
790876 /*
791877 * When targeting an LLVM version with opaque pointers enabled by default,
792878 * turn them off for the context we build our code in. We don't need to
@@ -803,6 +889,11 @@ llvm_session_initialize(void)
803889 */
804890 llvm_create_types ();
805891
892+ /*
893+ * Extract target information from loaded module.
894+ */
895+ llvm_set_target ();
896+
806897 if (LLVMGetTargetFromTriple (llvm_triple , & llvm_targetref , & error ) != 0 )
807898 {
808899 elog (FATAL , "failed to query triple %s" , error );
@@ -898,6 +989,10 @@ llvm_shutdown(int code, Datum arg)
898989 return ;
899990 }
900991
992+ if (llvm_jit_context_in_use_count != 0 )
993+ elog (PANIC , "LLVMJitContext in use count not 0 at exit (is %zu)" ,
994+ llvm_jit_context_in_use_count );
995+
901996#if LLVM_VERSION_MAJOR > 11
902997 {
903998 if (llvm_opt3_orc )
@@ -968,6 +1063,23 @@ load_return_type(LLVMModuleRef mod, const char *name)
9681063 return typ ;
9691064}
9701065
1066+ /*
1067+ * Load triple & layout from clang emitted file so we're guaranteed to be
1068+ * compatible.
1069+ */
1070+ static void
1071+ llvm_set_target (void )
1072+ {
1073+ if (!llvm_types_module )
1074+ elog (ERROR , "failed to extract target information, llvmjit_types.c not loaded" );
1075+
1076+ if (llvm_triple == NULL )
1077+ llvm_triple = pstrdup (LLVMGetTarget (llvm_types_module ));
1078+
1079+ if (llvm_layout == NULL )
1080+ llvm_layout = pstrdup (LLVMGetDataLayoutStr (llvm_types_module ));
1081+ }
1082+
9711083/*
9721084 * Load required information, types, function signatures from llvmjit_types.c
9731085 * and make them available in global variables.
@@ -991,19 +1103,12 @@ llvm_create_types(void)
9911103 }
9921104
9931105 /* eagerly load contents, going to need it all */
994- if (LLVMParseBitcode2 ( buf , & llvm_types_module ))
1106+ if (LLVMParseBitcodeInContext2 ( llvm_context , buf , & llvm_types_module ))
9951107 {
996- elog (ERROR , "LLVMParseBitcode2 of %s failed" , path );
1108+ elog (ERROR , "LLVMParseBitcodeInContext2 of %s failed" , path );
9971109 }
9981110 LLVMDisposeMemoryBuffer (buf );
9991111
1000- /*
1001- * Load triple & layout from clang emitted file so we're guaranteed to be
1002- * compatible.
1003- */
1004- llvm_triple = pstrdup (LLVMGetTarget (llvm_types_module ));
1005- llvm_layout = pstrdup (LLVMGetDataLayoutStr (llvm_types_module ));
1006-
10071112 TypeSizeT = llvm_pg_var_type ("TypeSizeT" );
10081113 TypeParamBool = load_return_type (llvm_types_module , "FunctionReturningBool" );
10091114 TypeStorageBool = llvm_pg_var_type ("TypeStorageBool" );
0 commit comments